Import Tint changes from Dawn

Changes:
  - 8ef731141397bc0d4a2d474ffbdd55c417ca860f tint: validate max number of members in a struct by Antonio Maiorano <amaiorano@google.com>
  - 8cd5c611fcc7d78c4871443128a1b18597443737 tint/reader/wgsl: Remove element_count_expression() by Ben Clayton <bclayton@google.com>
  - dec0c62997bc037bc6a88be39a6939d5a479bf1b tint: optimize SymbolTable::New by Antonio Maiorano <amaiorano@google.com>
  - 66d487395d293c983bde13e14709df6eb2bb01e4 tint: Use PI/2 as the input value for sin tests by James Price <jrprice@google.com>
  - 1a1b5278d5f807cb8e510df541913c8d223aa833 tint/transform: Inline HLSL uniform / storage buffers by Ben Clayton <bclayton@google.com>
  - 7052cb57ff6b5463531640c386ae0798ed4f225f Revert "Add test setting the locale." by Ben Clayton <bclayton@google.com>
  - 65a45fdf419d77a470c18a344126d2299632db82 Handle errors in SPIRV-Reader tests. by dan sinclair <dsinclair@chromium.org>
  - 107aa81c891a5a5938375d7bdbae028b579ebfd6 tint: Improve error for assignment to immutable variable by Ben Clayton <bclayton@google.com>
  - 9cdc3343ff2f88e44bbc2f43feb2c0f05b3e03ad Add test setting the locale. by dan sinclair <dsinclair@chromium.org>
  - 077d97a387bf41700fadccbc2b95df24162682b8 Add `SuggestAlternatives` to attributes. by dan sinclair <dsinclair@chromium.org>
  - 9386f73446d8aa997a213c0ed910d923cfcf032a tint: Fix compilation error with latest MSVC 17.5.0 by Antonio Maiorano <amaiorano@google.com>
  - 869bcabf88bc521ef209f9f9f1c6a5449c1478cd Make attribute grammar generic. by dan sinclair <dsinclair@chromium.org>
  - 39b7330b5b509e7c4111faf17f6f489d719bc319 Fix UV coord for TextureLoad by jchen10 <jie.a.chen@intel.com>
  - 9776edf161586a7686bab13d9aa03a62c1d11204 tint: Improve error message for array element stride in u... by Antonio Maiorano <amaiorano@google.com>
  - 187e0d5fe78c5996e93d5bb2981e2b16a88291db Add `requires` directive by dan sinclair <dsinclair@chromium.org>
  - 54a104e28f4a8d86c80dd9e0905d54e34009cc0a tint: Update constructor / conversion terminology by Ben Clayton <bclayton@google.com>
  - afc53fa942b86e219620ec67ae4f9a268c0918e8 tint/resolver: Bring back enum suggestions by Ben Clayton <bclayton@google.com>
  - b549b3051e3c04350d428527fc9b3e015d1b44a2 tint: Validate @must_use on functions and builtins by Ben Clayton <bclayton@google.com>
  - d84903201db21eb69d28a80b65297cff9d826fc6 tools: Add @must_use support to intrinsics.def by Ben Clayton <bclayton@google.com>
  - ce10962d82e43f65de0f2be56a617b9b9376f812 Add parsing and emission of the `must_use` attribute. by dan sinclair <dsinclair@chromium.org>
  - 5662f79b24f031f8350f2f3811d2940df2ab0dfc tint/ast: Remove unnecessary ast:: prefixes by Ben Clayton <bclayton@google.com>
  - 239b4298b3673e92c3ca8c96ad6e858431ad9181 tint/HoistToDeclBefore: Use explicit types by James Price <jrprice@google.com>
  - 60d373810230b1cc6246122e1c63ab0eccb8bbf5 tint: Fix ICE in ast::TemplatedIdentifier ctor by Ben Clayton <bclayton@google.com>
  - 2f689a7efe70d0ca86b195a04cc6bdaceb84e5cf Remove deprecated inspector fields. by dan sinclair <dsinclair@chromium.org>
  - fdef03321033af75c363d7f40ab33ada91c965bb tint/resolver: Fix ICE in ResolvedIdentifier::String() by Ben Clayton <bclayton@google.com>
  - f0b4dbb82dcde3e9ea152a459a5865bc3d93b3dc tint: Resolve @interpolate() args as expressions by Ben Clayton <bclayton@google.com>
  - a79c6603b2e787a0da8ef1e517eda4522baa5f09 Add `@must_use` AST node. by dan sinclair <dsinclair@chromium.org>
  - b92ff397245c97989e8efbb723dfea9f2719185c Remove `static_assert` deprecation. by dan sinclair <dsinclair@chromium.org>
  - 4d3ff9711e55d049ec4d1979db49eaa74fa4a3b8 tint: Resolve @builtin() args as expressions by Ben Clayton <bclayton@google.com>
  - 21571709a2f6ef64596956b78762f35bdc96ccc0 Remove the `type` keyword. by dan sinclair <dsinclair@chromium.org>
  - 2d6f90771b4745441e281aee5d40d4148a508bfc tint/reader/spirv: Remove stdout spam by Ben Clayton <bclayton@google.com>
  - 993a658af2a40bc9ac9c3db42bb26f0b3736cf04 Move InterpolationSampling and InterpolationType to built... by dan sinclair <dsinclair@chromium.org>
  - b5af23d5880d0f2f5ecb3517bc8a92b685c778c4 Move diagnostic severity and rule to builtin. by dan sinclair <dsinclair@chromium.org>
  - ef30aa400c104445c2d81f50ec37c359a41538e9 Move type/builtin to builtin. by dan sinclair <dsinclair@chromium.org>
  - ba082fdb48fab870d11acc9e60eaf6afe76aa180 Move TexelFormat to builtin by dan sinclair <dsinclair@chromium.org>
  - 2a65163c6d4843e417bf60e9aa282eeb5e89bc04 Move type::AddressSpace to builtin/ by dan sinclair <dsinclair@chromium.org>
  - b6cc4cbf896855201079030d28feb2070e020e54 Move type/access to builtin. by dan sinclair <dsinclair@chromium.org>
  - 79781f26d1fc525fb9c3ba291e5660ea3da6eeb1 tint: Unkeyword 'var' template args by Ben Clayton <bclayton@google.com>
  - 1b90f937422b1526245f3224194a99c0ed5ee5bc tint: Remove type::AddressSpace::kNone by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: 8ef731141397bc0d4a2d474ffbdd55c417ca860f
Change-Id: I86c586f9f089f2c8e2a0cf07d809b85ec5d3a16b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/120523
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index dd679c7..662f90d 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -218,6 +218,7 @@
     "utils/map.h",
     "utils/math.h",
     "utils/scoped_assignment.h",
+    "utils/slice.h",
     "utils/string.cc",
     "utils/string.h",
     "utils/unique_allocator.h",
@@ -248,10 +249,10 @@
     "program_builder.cc",
     "resolver/const_eval.cc",
     "resolver/const_eval.h",
+    "resolver/ctor_conv_intrinsic.cc",
+    "resolver/ctor_conv_intrinsic.h",
     "resolver/dependency_graph.cc",
     "resolver/dependency_graph.h",
-    "resolver/init_conv_intrinsic.cc",
-    "resolver/init_conv_intrinsic.h",
     "resolver/intrinsic_table.cc",
     "resolver/intrinsic_table.h",
     "resolver/intrinsic_table.inl",
@@ -490,6 +491,7 @@
     "ast/loop_statement.h",
     "ast/member_accessor_expression.h",
     "ast/module.h",
+    "ast/must_use_attribute.h",
     "ast/node.h",
     "ast/node_id.h",
     "ast/override.h",
@@ -575,6 +577,7 @@
     "ast/loop_statement.cc",
     "ast/member_accessor_expression.cc",
     "ast/module.cc",
+    "ast/must_use_attribute.cc",
     "ast/node.cc",
     "ast/override.cc",
     "ast/parameter.cc",
@@ -604,6 +607,7 @@
   public_deps = [ ":libtint_ast_hdrs" ]
   deps = [
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_program_src",
     ":libtint_type_src",
   ]
@@ -667,13 +671,13 @@
     "sem/struct.h",
     "sem/switch_statement.cc",
     "sem/switch_statement.h",
-    "sem/type_conversion.cc",
-    "sem/type_conversion.h",
     "sem/type_expression.cc",
     "sem/type_expression.h",
-    "sem/type_initializer.cc",
-    "sem/type_initializer.h",
     "sem/type_mappings.h",
+    "sem/value_constructor.cc",
+    "sem/value_constructor.h",
+    "sem/value_conversion.cc",
+    "sem/value_conversion.h",
     "sem/value_expression.cc",
     "sem/value_expression.h",
     "sem/variable.cc",
@@ -693,10 +697,28 @@
 
 libtint_source_set("libtint_builtins_src") {
   sources = [
+    "builtin/access.cc",
+    "builtin/access.h",
+    "builtin/address_space.cc",
+    "builtin/address_space.h",
+    "builtin/attribute.cc",
+    "builtin/attribute.h",
+    "builtin/builtin.cc",
+    "builtin/builtin.h",
     "builtin/builtin_value.cc",
     "builtin/builtin_value.h",
+    "builtin/diagnostic_rule.cc",
+    "builtin/diagnostic_rule.h",
+    "builtin/diagnostic_severity.cc",
+    "builtin/diagnostic_severity.h",
     "builtin/extension.cc",
     "builtin/extension.h",
+    "builtin/interpolation_sampling.cc",
+    "builtin/interpolation_sampling.h",
+    "builtin/interpolation_type.cc",
+    "builtin/interpolation_type.h",
+    "builtin/texel_format.cc",
+    "builtin/texel_format.h",
   ]
   deps = [ ":libtint_base_src" ]
 }
@@ -709,10 +731,6 @@
     "type/abstract_int.h",
     "type/abstract_numeric.cc",
     "type/abstract_numeric.h",
-    "type/access.cc",
-    "type/access.h",
-    "type/address_space.cc",
-    "type/address_space.h",
     "type/array.cc",
     "type/array.h",
     "type/array_count.cc",
@@ -721,8 +739,6 @@
     "type/atomic.h",
     "type/bool.cc",
     "type/bool.h",
-    "type/builtin.cc",
-    "type/builtin.h",
     "type/clone_context.h",
     "type/depth_multisampled_texture.cc",
     "type/depth_multisampled_texture.h",
@@ -758,8 +774,6 @@
     "type/storage_texture.h",
     "type/struct.cc",
     "type/struct.h",
-    "type/texel_format.cc",
-    "type/texel_format.h",
     "type/texture.cc",
     "type/texture.h",
     "type/texture_dimension.cc",
@@ -776,7 +790,10 @@
     "type/void.h",
   ]
 
-  deps = [ ":libtint_base_src" ]
+  deps = [
+    ":libtint_base_src",
+    ":libtint_builtins_src",
+  ]
 }
 
 libtint_source_set("libtint_constant_src") {
@@ -813,6 +830,7 @@
 
 libtint_source_set("libtint_spv_reader_src") {
   sources = [
+    "reader/spirv/attributes.h",
     "reader/spirv/construct.cc",
     "reader/spirv/construct.h",
     "reader/spirv/entry_point_info.cc",
@@ -904,6 +922,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_constant_src",
     ":libtint_program_src",
     ":libtint_sem_src",
@@ -931,6 +950,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_program_src",
     ":libtint_reader_src",
     ":libtint_text_src",
@@ -949,6 +969,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_program_src",
     ":libtint_sem_src",
     ":libtint_type_src",
@@ -967,6 +988,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_constant_src",
     ":libtint_program_src",
     ":libtint_sem_src",
@@ -987,6 +1009,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_constant_src",
     ":libtint_program_src",
     ":libtint_sem_src",
@@ -1007,6 +1030,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_constant_src",
     ":libtint_program_src",
     ":libtint_sem_src",
@@ -1249,7 +1273,6 @@
       "ast/index_accessor_expression_test.cc",
       "ast/int_literal_expression_test.cc",
       "ast/interpolate_attribute_test.cc",
-      "ast/invariant_attribute_test.cc",
       "ast/location_attribute_test.cc",
       "ast/loop_statement_test.cc",
       "ast/member_accessor_expression_test.cc",
@@ -1275,6 +1298,7 @@
     deps = [
       ":libtint_ast_src",
       ":libtint_base_src",
+      ":libtint_builtins_src",
       ":libtint_transform_src",
       ":libtint_unittests_ast_helper",
     ]
@@ -1287,8 +1311,17 @@
 
   tint_unittests_source_set("tint_unittests_builtins_src") {
     sources = [
+      "builtin/access_test.cc",
+      "builtin/address_space_test.cc",
+      "builtin/attribute_test.cc",
+      "builtin/builtin_test.cc",
       "builtin/builtin_value_test.cc",
+      "builtin/diagnostic_rule_test.cc",
+      "builtin/diagnostic_severity_test.cc",
       "builtin/extension_test.cc",
+      "builtin/interpolation_sampling_test.cc",
+      "builtin/interpolation_type_test.cc",
+      "builtin/texel_format_test.cc",
     ]
     deps = [ ":libtint_builtins_src" ]
   }
@@ -1370,11 +1403,12 @@
       "resolver/struct_address_space_use_test.cc",
       "resolver/struct_layout_test.cc",
       "resolver/struct_pipeline_stage_use_test.cc",
-      "resolver/type_initializer_validation_test.cc",
       "resolver/type_validation_test.cc",
       "resolver/uniformity_test.cc",
+      "resolver/unresolved_identifier_test.cc",
       "resolver/validation_test.cc",
       "resolver/validator_is_storeable_test.cc",
+      "resolver/value_constructor_validation_test.cc",
       "resolver/variable_test.cc",
       "resolver/variable_validation_test.cc",
     ]
@@ -1405,11 +1439,8 @@
 
   tint_unittests_source_set("tint_unittests_type_src") {
     sources = [
-      "type/access_test.cc",
-      "type/address_space_test.cc",
       "type/atomic_test.cc",
       "type/bool_test.cc",
-      "type/builtin_test.cc",
       "type/depth_multisampled_texture_test.cc",
       "type/depth_texture_test.cc",
       "type/external_texture_test.cc",
@@ -1425,13 +1456,15 @@
       "type/sampler_test.cc",
       "type/storage_texture_test.cc",
       "type/struct_test.cc",
-      "type/texel_format_test.cc",
       "type/texture_test.cc",
       "type/type_test.cc",
       "type/u32_test.cc",
       "type/vector_test.cc",
     ]
-    deps = [ ":libtint_base_src" ]
+    deps = [
+      ":libtint_base_src",
+      ":libtint_builtins_src",
+    ]
   }
 
   tint_unittests_source_set("tint_unittests_text_src") {
@@ -1499,6 +1532,7 @@
 
     deps = [
       ":libtint_base_src",
+      ":libtint_builtins_src",
       ":libtint_transform_src",
       ":libtint_unittests_ast_helper",
       ":libtint_wgsl_reader_src",
@@ -1524,6 +1558,7 @@
       "utils/result_test.cc",
       "utils/reverse_test.cc",
       "utils/scoped_assignment_test.cc",
+      "utils/slice_test.cc",
       "utils/string_test.cc",
       "utils/transform_test.cc",
       "utils/unique_allocator_test.cc",
@@ -1607,6 +1642,7 @@
       "writer/spirv/builder_builtin_texture_test.cc",
       "writer/spirv/builder_call_test.cc",
       "writer/spirv/builder_const_assert_test.cc",
+      "writer/spirv/builder_constructor_expression_test.cc",
       "writer/spirv/builder_discard_test.cc",
       "writer/spirv/builder_entry_point_test.cc",
       "writer/spirv/builder_format_conversion_test.cc",
@@ -1616,7 +1652,6 @@
       "writer/spirv/builder_global_variable_test.cc",
       "writer/spirv/builder_ident_expression_test.cc",
       "writer/spirv/builder_if_test.cc",
-      "writer/spirv/builder_initializer_expression_test.cc",
       "writer/spirv/builder_literal_test.cc",
       "writer/spirv/builder_loop_test.cc",
       "writer/spirv/builder_return_test.cc",
@@ -1646,7 +1681,6 @@
       "reader/wgsl/classify_template_args_test.cc",
       "reader/wgsl/lexer_test.cc",
       "reader/wgsl/parser_impl_additive_expression_test.cc",
-      "reader/wgsl/parser_impl_address_space_test.cc",
       "reader/wgsl/parser_impl_argument_expression_list_test.cc",
       "reader/wgsl/parser_impl_assignment_stmt_test.cc",
       "reader/wgsl/parser_impl_bitwise_expression_test.cc",
@@ -1662,7 +1696,6 @@
       "reader/wgsl/parser_impl_diagnostic_attribute_test.cc",
       "reader/wgsl/parser_impl_diagnostic_control_test.cc",
       "reader/wgsl/parser_impl_diagnostic_directive_test.cc",
-      "reader/wgsl/parser_impl_element_count_expression_test.cc",
       "reader/wgsl/parser_impl_enable_directive_test.cc",
       "reader/wgsl/parser_impl_error_msg_test.cc",
       "reader/wgsl/parser_impl_error_resync_test.cc",
@@ -1685,6 +1718,7 @@
       "reader/wgsl/parser_impl_paren_expression_test.cc",
       "reader/wgsl/parser_impl_primary_expression_test.cc",
       "reader/wgsl/parser_impl_relational_expression_test.cc",
+      "reader/wgsl/parser_impl_require_directive_test.cc",
       "reader/wgsl/parser_impl_reserved_keyword_test.cc",
       "reader/wgsl/parser_impl_shift_expression_test.cc",
       "reader/wgsl/parser_impl_singular_expression_test.cc",
@@ -1717,6 +1751,7 @@
 
     deps = [
       ":libtint_base_src",
+      ":libtint_builtins_src",
       ":libtint_unittests_ast_helper",
       ":libtint_wgsl_reader_src",
     ]
@@ -1735,6 +1770,7 @@
       "writer/wgsl/generator_impl_case_test.cc",
       "writer/wgsl/generator_impl_cast_test.cc",
       "writer/wgsl/generator_impl_const_assert_test.cc",
+      "writer/wgsl/generator_impl_constructor_test.cc",
       "writer/wgsl/generator_impl_continue_test.cc",
       "writer/wgsl/generator_impl_diagnostic_test.cc",
       "writer/wgsl/generator_impl_discard_test.cc",
@@ -1743,7 +1779,6 @@
       "writer/wgsl/generator_impl_global_decl_test.cc",
       "writer/wgsl/generator_impl_identifier_test.cc",
       "writer/wgsl/generator_impl_if_test.cc",
-      "writer/wgsl/generator_impl_initializer_test.cc",
       "writer/wgsl/generator_impl_literal_test.cc",
       "writer/wgsl/generator_impl_loop_test.cc",
       "writer/wgsl/generator_impl_member_accessor_test.cc",
@@ -1758,6 +1793,7 @@
     ]
 
     deps = [
+      ":libtint_builtins_src",
       ":libtint_wgsl_writer_src",
       ":tint_unittests_ast_src",
     ]
@@ -1777,13 +1813,13 @@
       "writer/msl/generator_impl_case_test.cc",
       "writer/msl/generator_impl_cast_test.cc",
       "writer/msl/generator_impl_const_assert_test.cc",
+      "writer/msl/generator_impl_constructor_test.cc",
       "writer/msl/generator_impl_continue_test.cc",
       "writer/msl/generator_impl_discard_test.cc",
       "writer/msl/generator_impl_function_test.cc",
       "writer/msl/generator_impl_identifier_test.cc",
       "writer/msl/generator_impl_if_test.cc",
       "writer/msl/generator_impl_import_test.cc",
-      "writer/msl/generator_impl_initializer_test.cc",
       "writer/msl/generator_impl_loop_test.cc",
       "writer/msl/generator_impl_member_accessor_test.cc",
       "writer/msl/generator_impl_module_constant_test.cc",
@@ -1817,13 +1853,13 @@
       "writer/hlsl/generator_impl_case_test.cc",
       "writer/hlsl/generator_impl_cast_test.cc",
       "writer/hlsl/generator_impl_const_assert_test.cc",
+      "writer/hlsl/generator_impl_constructor_test.cc",
       "writer/hlsl/generator_impl_continue_test.cc",
       "writer/hlsl/generator_impl_discard_test.cc",
       "writer/hlsl/generator_impl_function_test.cc",
       "writer/hlsl/generator_impl_identifier_test.cc",
       "writer/hlsl/generator_impl_if_test.cc",
       "writer/hlsl/generator_impl_import_test.cc",
-      "writer/hlsl/generator_impl_initializer_test.cc",
       "writer/hlsl/generator_impl_loop_test.cc",
       "writer/hlsl/generator_impl_member_accessor_test.cc",
       "writer/hlsl/generator_impl_module_constant_test.cc",
@@ -1858,13 +1894,13 @@
       "writer/glsl/generator_impl_call_test.cc",
       "writer/glsl/generator_impl_case_test.cc",
       "writer/glsl/generator_impl_cast_test.cc",
+      "writer/glsl/generator_impl_constructor_test.cc",
       "writer/glsl/generator_impl_continue_test.cc",
       "writer/glsl/generator_impl_discard_test.cc",
       "writer/glsl/generator_impl_function_test.cc",
       "writer/glsl/generator_impl_identifier_test.cc",
       "writer/glsl/generator_impl_if_test.cc",
       "writer/glsl/generator_impl_import_test.cc",
-      "writer/glsl/generator_impl_initializer_test.cc",
       "writer/glsl/generator_impl_loop_test.cc",
       "writer/glsl/generator_impl_member_accessor_test.cc",
       "writer/glsl/generator_impl_module_constant_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 67ca5e9..658d14f 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -158,6 +158,8 @@
   ast/int_literal_expression.h
   ast/internal_attribute.cc
   ast/internal_attribute.h
+  ast/interpolate_attribute.cc
+  ast/interpolate_attribute.h
   ast/invariant_attribute.cc
   ast/invariant_attribute.h
   ast/let.cc
@@ -172,6 +174,8 @@
   ast/member_accessor_expression.h
   ast/module.cc
   ast/module.h
+  ast/must_use_attribute.cc
+  ast/must_use_attribute.h
   ast/node_id.h
   ast/node.cc
   ast/node.h
@@ -327,12 +331,12 @@
   sem/switch_statement.h
   sem/type_expression.cc
   sem/type_expression.h
-  sem/type_initializer.cc
-  sem/type_initializer.h
-  sem/type_conversion.cc
-  sem/type_conversion.h
   sem/type_mappings.h
   sem/variable.cc
+  sem/value_constructor.cc
+  sem/value_constructor.h
+  sem/value_conversion.cc
+  sem/value_conversion.h
   sem/value_expression.cc
   sem/value_expression.h
   sem/while_statement.cc
@@ -523,6 +527,7 @@
   utils/map.h
   utils/math.h
   utils/scoped_assignment.h
+  utils/slice.h
   utils/string.cc
   utils/string.h
   utils/unique_allocator.h
@@ -548,17 +553,21 @@
   writer/writer.h
 )
 
+tint_generated(builtin/access BENCH TEST)
+tint_generated(builtin/address_space BENCH TEST)
+tint_generated(builtin/attribute BENCH TEST)
+tint_generated(builtin/builtin BENCH TEST)
 tint_generated(builtin/builtin_value BENCH TEST)
+tint_generated(builtin/diagnostic_rule BENCH TEST)
+tint_generated(builtin/diagnostic_severity BENCH TEST)
 tint_generated(builtin/extension BENCH TEST)
-tint_generated(ast/diagnostic_control BENCH TEST)
-tint_generated(ast/interpolate_attribute BENCH TEST)
-tint_generated(resolver/init_conv_intrinsic)
+tint_generated(builtin/interpolation_sampling BENCH TEST)
+tint_generated(builtin/interpolation_type BENCH TEST)
+tint_generated(builtin/texel_format BENCH TEST)
+
+tint_generated(resolver/ctor_conv_intrinsic)
 tint_generated(sem/builtin_type)
 tint_generated(sem/parameter_usage)
-tint_generated(type/access BENCH TEST)
-tint_generated(type/address_space BENCH TEST)
-tint_generated(type/builtin BENCH TEST)
-tint_generated(type/texel_format BENCH TEST)
 
 if(UNIX)
   list(APPEND TINT_LIB_SRCS diagnostic/printer_posix.cc)
@@ -570,6 +579,7 @@
 
 if(${TINT_BUILD_SPV_READER})
   list(APPEND TINT_LIB_SRCS
+    reader/spirv/attributes.h
     reader/spirv/construct.h
     reader/spirv/construct.cc
     reader/spirv/entry_point_info.h
@@ -824,7 +834,7 @@
     ast/increment_decrement_statement_test.cc
     ast/index_accessor_expression_test.cc
     ast/int_literal_expression_test.cc
-    ast/invariant_attribute_test.cc
+    ast/interpolate_attribute_test.cc
     ast/location_attribute_test.cc
     ast/loop_statement_test.cc
     ast/member_accessor_expression_test.cc
@@ -917,10 +927,11 @@
     resolver/struct_layout_test.cc
     resolver/struct_pipeline_stage_use_test.cc
     resolver/struct_address_space_use_test.cc
-    resolver/type_initializer_validation_test.cc
     resolver/type_validation_test.cc
+    resolver/unresolved_identifier_test.cc
     resolver/validation_test.cc
     resolver/validator_is_storeable_test.cc
+    resolver/value_constructor_validation_test.cc
     resolver/variable_test.cc
     resolver/variable_validation_test.cc
     scope_stack_test.cc
@@ -973,6 +984,7 @@
     utils/result_test.cc
     utils/reverse_test.cc
     utils/scoped_assignment_test.cc
+    utils/slice_test.cc
     utils/string_test.cc
     utils/transform_test.cc
     utils/unique_allocator_test.cc
@@ -1064,7 +1076,6 @@
       reader/wgsl/parser_impl_diagnostic_attribute_test.cc
       reader/wgsl/parser_impl_diagnostic_control_test.cc
       reader/wgsl/parser_impl_diagnostic_directive_test.cc
-      reader/wgsl/parser_impl_element_count_expression_test.cc
       reader/wgsl/parser_impl_enable_directive_test.cc
       reader/wgsl/parser_impl_error_msg_test.cc
       reader/wgsl/parser_impl_error_resync_test.cc
@@ -1088,11 +1099,11 @@
       reader/wgsl/parser_impl_primary_expression_test.cc
       reader/wgsl/parser_impl_relational_expression_test.cc
       reader/wgsl/parser_impl_reserved_keyword_test.cc
+      reader/wgsl/parser_impl_require_directive_test.cc
       reader/wgsl/parser_impl_shift_expression_test.cc
       reader/wgsl/parser_impl_singular_expression_test.cc
       reader/wgsl/parser_impl_statement_test.cc
       reader/wgsl/parser_impl_statements_test.cc
-      reader/wgsl/parser_impl_address_space_test.cc
       reader/wgsl/parser_impl_struct_body_decl_test.cc
       reader/wgsl/parser_impl_struct_decl_test.cc
       reader/wgsl/parser_impl_struct_attribute_decl_test.cc
@@ -1130,6 +1141,7 @@
       writer/spirv/builder_builtin_texture_test.cc
       writer/spirv/builder_call_test.cc
       writer/spirv/builder_const_assert_test.cc
+      writer/spirv/builder_constructor_expression_test.cc
       writer/spirv/builder_discard_test.cc
       writer/spirv/builder_entry_point_test.cc
       writer/spirv/builder_format_conversion_test.cc
@@ -1139,7 +1151,6 @@
       writer/spirv/builder_global_variable_test.cc
       writer/spirv/builder_ident_expression_test.cc
       writer/spirv/builder_if_test.cc
-      writer/spirv/builder_initializer_expression_test.cc
       writer/spirv/builder_literal_test.cc
       writer/spirv/builder_loop_test.cc
       writer/spirv/builder_return_test.cc
@@ -1170,6 +1181,7 @@
       writer/wgsl/generator_impl_case_test.cc
       writer/wgsl/generator_impl_cast_test.cc
       writer/wgsl/generator_impl_const_assert_test.cc
+      writer/wgsl/generator_impl_constructor_test.cc
       writer/wgsl/generator_impl_continue_test.cc
       writer/wgsl/generator_impl_diagnostic_test.cc
       writer/wgsl/generator_impl_discard_test.cc
@@ -1178,7 +1190,6 @@
       writer/wgsl/generator_impl_global_decl_test.cc
       writer/wgsl/generator_impl_identifier_test.cc
       writer/wgsl/generator_impl_if_test.cc
-      writer/wgsl/generator_impl_initializer_test.cc
       writer/wgsl/generator_impl_loop_test.cc
       writer/wgsl/generator_impl_literal_test.cc
       writer/wgsl/generator_impl_member_accessor_test.cc
@@ -1266,12 +1277,12 @@
       writer/msl/generator_impl_case_test.cc
       writer/msl/generator_impl_cast_test.cc
       writer/msl/generator_impl_const_assert_test.cc
+      writer/msl/generator_impl_constructor_test.cc
       writer/msl/generator_impl_continue_test.cc
       writer/msl/generator_impl_discard_test.cc
       writer/msl/generator_impl_function_test.cc
       writer/msl/generator_impl_identifier_test.cc
       writer/msl/generator_impl_if_test.cc
-      writer/msl/generator_impl_initializer_test.cc
       writer/msl/generator_impl_import_test.cc
       writer/msl/generator_impl_loop_test.cc
       writer/msl/generator_impl_member_accessor_test.cc
@@ -1300,7 +1311,7 @@
       writer/glsl/generator_impl_call_test.cc
       writer/glsl/generator_impl_case_test.cc
       writer/glsl/generator_impl_cast_test.cc
-      writer/glsl/generator_impl_initializer_test.cc
+      writer/glsl/generator_impl_constructor_test.cc
       writer/glsl/generator_impl_continue_test.cc
       writer/glsl/generator_impl_discard_test.cc
       writer/glsl/generator_impl_function_test.cc
@@ -1338,12 +1349,12 @@
       writer/hlsl/generator_impl_case_test.cc
       writer/hlsl/generator_impl_cast_test.cc
       writer/hlsl/generator_impl_const_assert_test.cc
+      writer/hlsl/generator_impl_constructor_test.cc
       writer/hlsl/generator_impl_continue_test.cc
       writer/hlsl/generator_impl_discard_test.cc
       writer/hlsl/generator_impl_function_test.cc
       writer/hlsl/generator_impl_identifier_test.cc
       writer/hlsl/generator_impl_if_test.cc
-      writer/hlsl/generator_impl_initializer_test.cc
       writer/hlsl/generator_impl_import_test.cc
       writer/hlsl/generator_impl_loop_test.cc
       writer/hlsl/generator_impl_member_accessor_test.cc
diff --git a/src/tint/ast/alias_test.cc b/src/tint/ast/alias_test.cc
index 6e5d647..d99fb21 100644
--- a/src/tint/ast/alias_test.cc
+++ b/src/tint/ast/alias_test.cc
@@ -14,7 +14,7 @@
 
 #include "src/tint/ast/alias.h"
 #include "src/tint/ast/test_helper.h"
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/access.h"
 
 namespace tint::ast {
 namespace {
diff --git a/src/tint/ast/binary_expression.h b/src/tint/ast/binary_expression.h
index 323ab48..35ca308 100644
--- a/src/tint/ast/binary_expression.h
+++ b/src/tint/ast/binary_expression.h
@@ -127,11 +127,11 @@
 /// @returns true if the op is an arithmetic operation
 inline bool IsArithmetic(BinaryOp op) {
     switch (op) {
-        case ast::BinaryOp::kAdd:
-        case ast::BinaryOp::kSubtract:
-        case ast::BinaryOp::kMultiply:
-        case ast::BinaryOp::kDivide:
-        case ast::BinaryOp::kModulo:
+        case BinaryOp::kAdd:
+        case BinaryOp::kSubtract:
+        case BinaryOp::kMultiply:
+        case BinaryOp::kDivide:
+        case BinaryOp::kModulo:
             return true;
         default:
             return false;
@@ -142,12 +142,12 @@
 /// @returns true if the op is a comparison operation
 inline bool IsComparison(BinaryOp op) {
     switch (op) {
-        case ast::BinaryOp::kEqual:
-        case ast::BinaryOp::kNotEqual:
-        case ast::BinaryOp::kLessThan:
-        case ast::BinaryOp::kLessThanEqual:
-        case ast::BinaryOp::kGreaterThan:
-        case ast::BinaryOp::kGreaterThanEqual:
+        case BinaryOp::kEqual:
+        case BinaryOp::kNotEqual:
+        case BinaryOp::kLessThan:
+        case BinaryOp::kLessThanEqual:
+        case BinaryOp::kGreaterThan:
+        case BinaryOp::kGreaterThanEqual:
             return true;
         default:
             return false;
@@ -158,9 +158,9 @@
 /// @returns true if the op is a bitwise operation
 inline bool IsBitwise(BinaryOp op) {
     switch (op) {
-        case ast::BinaryOp::kAnd:
-        case ast::BinaryOp::kOr:
-        case ast::BinaryOp::kXor:
+        case BinaryOp::kAnd:
+        case BinaryOp::kOr:
+        case BinaryOp::kXor:
             return true;
         default:
             return false;
@@ -171,8 +171,8 @@
 /// @returns true if the op is a bit shift operation
 inline bool IsBitshift(BinaryOp op) {
     switch (op) {
-        case ast::BinaryOp::kShiftLeft:
-        case ast::BinaryOp::kShiftRight:
+        case BinaryOp::kShiftLeft:
+        case BinaryOp::kShiftRight:
             return true;
         default:
             return false;
@@ -181,8 +181,8 @@
 
 inline bool BinaryExpression::IsLogical() const {
     switch (op) {
-        case ast::BinaryOp::kLogicalAnd:
-        case ast::BinaryOp::kLogicalOr:
+        case BinaryOp::kLogicalAnd:
+        case BinaryOp::kLogicalOr:
             return true;
         default:
             return false;
diff --git a/src/tint/ast/binding_attribute.cc b/src/tint/ast/binding_attribute.cc
index 38f1d0f..1b08b28 100644
--- a/src/tint/ast/binding_attribute.cc
+++ b/src/tint/ast/binding_attribute.cc
@@ -25,7 +25,7 @@
 BindingAttribute::BindingAttribute(ProgramID pid,
                                    NodeID nid,
                                    const Source& src,
-                                   const ast::Expression* exp)
+                                   const Expression* exp)
     : Base(pid, nid, src), expr(exp) {}
 
 BindingAttribute::~BindingAttribute() = default;
diff --git a/src/tint/ast/binding_attribute.h b/src/tint/ast/binding_attribute.h
index 7bb7add..3ff7c97 100644
--- a/src/tint/ast/binding_attribute.h
+++ b/src/tint/ast/binding_attribute.h
@@ -30,7 +30,7 @@
     /// @param nid the unique node identifier
     /// @param src the source of this node
     /// @param expr the binding expression
-    BindingAttribute(ProgramID pid, NodeID nid, const Source& src, const ast::Expression* expr);
+    BindingAttribute(ProgramID pid, NodeID nid, const Source& src, const Expression* expr);
     ~BindingAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -43,7 +43,7 @@
     const BindingAttribute* Clone(CloneContext* ctx) const override;
 
     /// the binding expression
-    const ast::Expression* const expr;
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/block_statement_test.cc b/src/tint/ast/block_statement_test.cc
index 5fc7910..3037508 100644
--- a/src/tint/ast/block_statement_test.cc
+++ b/src/tint/ast/block_statement_test.cc
@@ -45,8 +45,8 @@
     auto* d = create<DiscardStatement>();
     auto* ptr = d;
 
-    auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "foo");
-    auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "bar");
+    auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "foo");
+    auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "bar");
     auto* b = create<BlockStatement>(utils::Vector{d}, utils::Vector{attr1, attr2});
 
     ASSERT_EQ(b->statements.Length(), 1u);
@@ -63,8 +63,7 @@
     EXPECT_FATAL_FAILURE(
         {
             ProgramBuilder b;
-            b.create<BlockStatement>(utils::Vector<const ast::Statement*, 1>{nullptr},
-                                     utils::Empty);
+            b.create<BlockStatement>(utils::Vector<const Statement*, 1>{nullptr}, utils::Empty);
         },
         "internal compiler error");
 }
diff --git a/src/tint/ast/builtin_attribute.cc b/src/tint/ast/builtin_attribute.cc
index e3f9d7b..44231c0 100644
--- a/src/tint/ast/builtin_attribute.cc
+++ b/src/tint/ast/builtin_attribute.cc
@@ -25,8 +25,10 @@
 BuiltinAttribute::BuiltinAttribute(ProgramID pid,
                                    NodeID nid,
                                    const Source& src,
-                                   builtin::BuiltinValue b)
-    : Base(pid, nid, src), builtin(b) {}
+                                   const Expression* b)
+    : Base(pid, nid, src), builtin(b) {
+    TINT_ASSERT_PROGRAM_IDS_EQUAL(AST, b, program_id);
+}
 
 BuiltinAttribute::~BuiltinAttribute() = default;
 
@@ -37,7 +39,8 @@
 const BuiltinAttribute* BuiltinAttribute::Clone(CloneContext* ctx) const {
     // Clone arguments outside of create() call to have deterministic ordering
     auto src = ctx->Clone(source);
-    return ctx->dst->create<BuiltinAttribute>(src, builtin);
+    auto b = ctx->Clone(builtin);
+    return ctx->dst->create<BuiltinAttribute>(src, b);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/builtin_attribute.h b/src/tint/ast/builtin_attribute.h
index 6f9b156..2ed6a2d 100644
--- a/src/tint/ast/builtin_attribute.h
+++ b/src/tint/ast/builtin_attribute.h
@@ -18,7 +18,11 @@
 #include <string>
 
 #include "src/tint/ast/attribute.h"
-#include "src/tint/builtin/builtin_value.h"
+
+// Forward declarations
+namespace tint::ast {
+class Expression;
+}
 
 namespace tint::ast {
 
@@ -30,7 +34,7 @@
     /// @param nid the unique node identifier
     /// @param src the source of this node
     /// @param builtin the builtin value
-    BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, builtin::BuiltinValue builtin);
+    BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, const Expression* builtin);
     ~BuiltinAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -43,7 +47,7 @@
     const BuiltinAttribute* Clone(CloneContext* ctx) const override;
 
     /// The builtin value
-    const builtin::BuiltinValue builtin;
+    const Expression* const builtin;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/builtin_attribute_test.cc b/src/tint/ast/builtin_attribute_test.cc
index 3421e0f..00192b8 100644
--- a/src/tint/ast/builtin_attribute_test.cc
+++ b/src/tint/ast/builtin_attribute_test.cc
@@ -12,7 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "gtest/gtest-spi.h"
+
 #include "src/tint/ast/test_helper.h"
+#include "src/tint/builtin/builtin_value.h"
 
 namespace tint::ast {
 namespace {
@@ -20,8 +23,27 @@
 using BuiltinAttributeTest = TestHelper;
 
 TEST_F(BuiltinAttributeTest, Creation) {
-    auto* d = create<BuiltinAttribute>(builtin::BuiltinValue::kFragDepth);
-    EXPECT_EQ(builtin::BuiltinValue::kFragDepth, d->builtin);
+    auto* d = Builtin(builtin::BuiltinValue::kFragDepth);
+    CheckIdentifier(Symbols(), d->builtin, "frag_depth");
+}
+
+TEST_F(BuiltinAttributeTest, Assert_Null_Builtin) {
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Builtin(nullptr);
+        },
+        "internal compiler error");
+}
+
+TEST_F(BuiltinAttributeTest, Assert_DifferentProgramID_Builtin) {
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Builtin(b2.Expr("bang"));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/builtin_texture_helper_test.cc b/src/tint/ast/builtin_texture_helper_test.cc
index 4aefbc6..6451bfe 100644
--- a/src/tint/ast/builtin_texture_helper_test.cc
+++ b/src/tint/ast/builtin_texture_helper_test.cc
@@ -14,6 +14,7 @@
 
 #include "src/tint/ast/builtin_texture_helper_test.h"
 
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/type/depth_texture.h"
 #include "src/tint/type/multisampled_texture.h"
 #include "src/tint/type/sampled_texture.h"
@@ -30,7 +31,8 @@
                                          type::TextureDimension dims,
                                          TextureDataType datatype,
                                          const char* f,
-                                         std::function<Args(ProgramBuilder*)> a)
+                                         std::function<Args(ProgramBuilder*)> a,
+                                         bool ret_val)
     : overload(o),
       description(desc),
       texture_kind(tk),
@@ -38,29 +40,33 @@
       texture_dimension(dims),
       texture_data_type(datatype),
       function(f),
-      args(std::move(a)) {}
+      args(std::move(a)),
+      returns_value(ret_val) {}
 TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
                                          const char* desc,
                                          TextureKind tk,
                                          type::TextureDimension dims,
                                          TextureDataType datatype,
                                          const char* f,
-                                         std::function<Args(ProgramBuilder*)> a)
+                                         std::function<Args(ProgramBuilder*)> a,
+                                         bool ret_val)
     : overload(o),
       description(desc),
       texture_kind(tk),
       texture_dimension(dims),
       texture_data_type(datatype),
       function(f),
-      args(std::move(a)) {}
+      args(std::move(a)),
+      returns_value(ret_val) {}
 TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
                                          const char* d,
-                                         type::Access acc,
-                                         type::TexelFormat fmt,
+                                         tint::builtin::Access acc,
+                                         tint::builtin::TexelFormat fmt,
                                          type::TextureDimension dims,
                                          TextureDataType datatype,
                                          const char* f,
-                                         std::function<Args(ProgramBuilder*)> a)
+                                         std::function<Args(ProgramBuilder*)> a,
+                                         bool ret_val)
     : overload(o),
       description(d),
       texture_kind(TextureKind::kStorage),
@@ -69,7 +75,8 @@
       texture_dimension(dims),
       texture_data_type(datatype),
       function(f),
-      args(std::move(a)) {}
+      args(std::move(a)),
+      returns_value(ret_val) {}
 TextureOverloadCase::TextureOverloadCase(const TextureOverloadCase&) = default;
 TextureOverloadCase::~TextureOverloadCase() = default;
 
@@ -127,13 +134,13 @@
     return out;
 }
 
-ast::Type TextureOverloadCase::BuildResultVectorComponentType(ProgramBuilder* b) const {
+Type TextureOverloadCase::BuildResultVectorComponentType(ProgramBuilder* b) const {
     switch (texture_data_type) {
-        case ast::builtin::test::TextureDataType::kF32:
+        case builtin::test::TextureDataType::kF32:
             return b->ty.f32();
-        case ast::builtin::test::TextureDataType::kU32:
+        case builtin::test::TextureDataType::kU32:
             return b->ty.u32();
-        case ast::builtin::test::TextureDataType::kI32:
+        case builtin::test::TextureDataType::kI32:
             return b->ty.i32();
     }
 
@@ -141,31 +148,31 @@
     return {};
 }
 
-const ast::Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b) const {
+const Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b) const {
     utils::Vector attrs{
         b->Group(0_u),
         b->Binding(0_a),
     };
     switch (texture_kind) {
-        case ast::builtin::test::TextureKind::kRegular:
+        case builtin::test::TextureKind::kRegular:
             return b->GlobalVar(
                 kTextureName,
                 b->ty.sampled_texture(texture_dimension, BuildResultVectorComponentType(b)), attrs);
 
-        case ast::builtin::test::TextureKind::kDepth:
+        case builtin::test::TextureKind::kDepth:
             return b->GlobalVar(kTextureName, b->ty.depth_texture(texture_dimension), attrs);
 
-        case ast::builtin::test::TextureKind::kDepthMultisampled:
+        case builtin::test::TextureKind::kDepthMultisampled:
             return b->GlobalVar(kTextureName, b->ty.depth_multisampled_texture(texture_dimension),
                                 attrs);
 
-        case ast::builtin::test::TextureKind::kMultisampled:
+        case builtin::test::TextureKind::kMultisampled:
             return b->GlobalVar(
                 kTextureName,
                 b->ty.multisampled_texture(texture_dimension, BuildResultVectorComponentType(b)),
                 attrs);
 
-        case ast::builtin::test::TextureKind::kStorage: {
+        case builtin::test::TextureKind::kStorage: {
             auto st = b->ty.storage_texture(texture_dimension, texel_format, access);
             return b->GlobalVar(kTextureName, st, attrs);
         }
@@ -175,7 +182,7 @@
     return nullptr;
 }
 
-const ast::Variable* TextureOverloadCase::BuildSamplerVariable(ProgramBuilder* b) const {
+const Variable* TextureOverloadCase::BuildSamplerVariable(ProgramBuilder* b) const {
     utils::Vector attrs = {b->Group(0_a), b->Binding(1_a)};
     return b->GlobalVar(kSamplerName, b->ty.sampler(sampler_kind), attrs);
 }
@@ -191,6 +198,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensions2d,
@@ -201,6 +209,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensions2dLevel,
@@ -212,6 +221,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensions2dArray,
@@ -222,6 +232,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensions2dArrayLevel,
@@ -233,6 +244,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensions3d,
@@ -243,6 +255,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensions3dLevel,
@@ -254,6 +267,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsCube,
@@ -264,6 +278,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsCubeLevel,
@@ -275,6 +290,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsCubeArray,
@@ -285,6 +301,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsCubeArrayLevel,
@@ -296,6 +313,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsMultisampled2d,
@@ -306,6 +324,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepth2d,
@@ -316,6 +335,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepth2dLevel,
@@ -327,6 +347,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepth2dArray,
@@ -337,6 +358,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepth2dArrayLevel,
@@ -348,6 +370,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepthCube,
@@ -358,6 +381,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepthCubeLevel,
@@ -369,6 +393,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepthCubeArray,
@@ -379,6 +404,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepthCubeArrayLevel,
@@ -390,6 +416,7 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName, 1_i); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsDepthMultisampled2d,
@@ -400,46 +427,51 @@
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsStorageWO1d,
             "textureDimensions(t : texture_storage_1d<rgba32float>) -> u32",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k1d,
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsStorageWO2d,
             "textureDimensions(t : texture_storage_2d<rgba32float>) -> vec2<u32>",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k2d,
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsStorageWO2dArray,
             "textureDimensions(t : texture_storage_2d_array<rgba32float>) -> vec2<u32>",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k2dArray,
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kDimensionsStorageWO3d,
             "textureDimensions(t : texture_storage_3d<rgba32float>) -> vec3<u32>",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k3d,
             TextureDataType::kF32,
             "textureDimensions",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
 
         {
@@ -459,6 +491,7 @@
                                    kSamplerName,             // s
                                    b->vec2<f32>(1_f, 2_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGather2dOffsetF32,
@@ -479,6 +512,7 @@
                                    b->vec2<f32>(1_f, 2_f),   // coords
                                    b->vec2<i32>(3_i, 4_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGather2dArrayF32,
@@ -499,6 +533,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_i);                    // array index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGather2dArrayOffsetF32,
@@ -521,6 +556,7 @@
                                    3_u,                      // array_index
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherCubeF32,
@@ -539,6 +575,7 @@
                                    kSamplerName,                  // s
                                    b->vec3<f32>(1_f, 2_f, 3_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherCubeArrayF32,
@@ -559,6 +596,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_u);                         // array_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherDepth2dF32,
@@ -575,6 +613,7 @@
                                    kSamplerName,             // s
                                    b->vec2<f32>(1_f, 2_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherDepth2dOffsetF32,
@@ -593,6 +632,7 @@
                                    b->vec2<f32>(1_f, 2_f),   // coords
                                    b->vec2<i32>(3_i, 4_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherDepth2dArrayF32,
@@ -611,6 +651,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_u);                    // array_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherDepth2dArrayOffsetF32,
@@ -631,6 +672,7 @@
                                    3_i,                      // array_index
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherDepthCubeF32,
@@ -647,6 +689,7 @@
                                    kSamplerName,                  // s
                                    b->vec3<f32>(1_f, 2_f, 3_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherDepthCubeArrayF32,
@@ -665,6 +708,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_u);                         // array_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherCompareDepth2dF32,
@@ -683,6 +727,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_f);                    // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherCompareDepth2dOffsetF32,
@@ -703,6 +748,7 @@
                                    3_f,                      // depth_ref
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherCompareDepth2dArrayF32,
@@ -723,6 +769,7 @@
                                    3_i,                     // array_index
                                    4_f);                    // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32,
@@ -745,6 +792,7 @@
                                    4_f,                      // depth_ref
                                    b->vec2<i32>(5_i, 6_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherCompareDepthCubeF32,
@@ -763,6 +811,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_f);                         // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kGatherCompareDepthCubeArrayF32,
@@ -783,6 +832,7 @@
                                    4_u,                          // array_index
                                    5_f);                         // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLayers2dArray,
@@ -793,6 +843,7 @@
             TextureDataType::kF32,
             "textureNumLayers",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLayersCubeArray,
@@ -803,6 +854,7 @@
             TextureDataType::kF32,
             "textureNumLayers",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLayersDepth2dArray,
@@ -813,6 +865,7 @@
             TextureDataType::kF32,
             "textureNumLayers",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLayersDepthCubeArray,
@@ -823,16 +876,18 @@
             TextureDataType::kF32,
             "textureNumLayers",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLayersStorageWO2dArray,
             "textureNumLayers(t : texture_storage_2d_array<rgba32float>) -> u32",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k2dArray,
             TextureDataType::kF32,
             "textureNumLayers",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevels2d,
@@ -843,6 +898,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevels2dArray,
@@ -853,6 +909,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevels3d,
@@ -863,6 +920,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevelsCube,
@@ -873,6 +931,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevelsCubeArray,
@@ -883,6 +942,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevelsDepth2d,
@@ -893,6 +953,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevelsDepth2dArray,
@@ -903,6 +964,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevelsDepthCube,
@@ -913,6 +975,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumLevelsDepthCubeArray,
@@ -923,6 +986,7 @@
             TextureDataType::kF32,
             "textureNumLevels",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumSamplesMultisampled2d,
@@ -933,6 +997,7 @@
             TextureDataType::kF32,
             "textureNumSamples",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kNumSamplesDepthMultisampled2d,
@@ -943,6 +1008,7 @@
             TextureDataType::kF32,
             "textureNumSamples",
             [](ProgramBuilder* b) { return b->ExprList(kTextureName); },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSample1dF32,
@@ -959,6 +1025,7 @@
                                    kSamplerName,  // s
                                    1_f);          // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSample2dF32,
@@ -975,6 +1042,7 @@
                                    kSamplerName,             // s
                                    b->vec2<f32>(1_f, 2_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSample2dOffsetF32,
@@ -993,6 +1061,7 @@
                                    b->vec2<f32>(1_f, 2_f),   // coords
                                    b->vec2<i32>(3_i, 4_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSample2dArrayF32,
@@ -1011,6 +1080,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_i);                    // array_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSample2dArrayOffsetF32,
@@ -1031,6 +1101,7 @@
                                    3_u,                      // array_index
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSample3dF32,
@@ -1047,6 +1118,7 @@
                                    kSamplerName,                  // s
                                    b->vec3<f32>(1_f, 2_f, 3_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSample3dOffsetF32,
@@ -1065,6 +1137,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),   // coords
                                    b->vec3<i32>(4_i, 5_i, 6_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCubeF32,
@@ -1081,6 +1154,7 @@
                                    kSamplerName,                  // s
                                    b->vec3<f32>(1_f, 2_f, 3_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCubeArrayF32,
@@ -1099,6 +1173,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_i);                         // array_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleDepth2dF32,
@@ -1115,6 +1190,7 @@
                                    kSamplerName,             // s
                                    b->vec2<f32>(1_f, 2_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleDepth2dOffsetF32,
@@ -1133,6 +1209,7 @@
                                    b->vec2<f32>(1_f, 2_f),   // coords
                                    b->vec2<i32>(3_i, 4_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleDepth2dArrayF32,
@@ -1151,6 +1228,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_i);                    // array_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleDepth2dArrayOffsetF32,
@@ -1171,6 +1249,7 @@
                                    3_i,                      // array_index
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleDepthCubeF32,
@@ -1187,6 +1266,7 @@
                                    kSamplerName,                  // s
                                    b->vec3<f32>(1_f, 2_f, 3_f));  // coords
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleDepthCubeArrayF32,
@@ -1205,6 +1285,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_u);                         // array_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleBias2dF32,
@@ -1223,6 +1304,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_f);                    // bias
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleBias2dOffsetF32,
@@ -1243,6 +1325,7 @@
                                    3_f,                      // bias
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleBias2dArrayF32,
@@ -1263,6 +1346,7 @@
                                    4_u,                     // array_index
                                    3_f);                    // bias
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleBias2dArrayOffsetF32,
@@ -1285,6 +1369,7 @@
                                    4_f,                      // bias
                                    b->vec2<i32>(5_i, 6_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleBias3dF32,
@@ -1303,6 +1388,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_f);                         // bias
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleBias3dOffsetF32,
@@ -1323,6 +1409,7 @@
                                    4_f,                           // bias
                                    b->vec3<i32>(5_i, 6_i, 7_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleBiasCubeF32,
@@ -1341,6 +1428,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_f);                         // bias
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleBiasCubeArrayF32,
@@ -1361,6 +1449,7 @@
                                    3_i,                          // array_index
                                    4_f);                         // bias
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevel2dF32,
@@ -1379,6 +1468,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_f);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevel2dOffsetF32,
@@ -1399,6 +1489,7 @@
                                    3_f,                      // level
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevel2dArrayF32,
@@ -1419,6 +1510,7 @@
                                    3_i,                     // array_index
                                    4_f);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevel2dArrayOffsetF32,
@@ -1441,6 +1533,7 @@
                                    4_f,                      // level
                                    b->vec2<i32>(5_i, 6_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevel3dF32,
@@ -1459,6 +1552,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_f);                         // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevel3dOffsetF32,
@@ -1479,6 +1573,7 @@
                                    4_f,                           // level
                                    b->vec3<i32>(5_i, 6_i, 7_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevelCubeF32,
@@ -1497,6 +1592,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_f);                         // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevelCubeArrayF32,
@@ -1517,6 +1613,7 @@
                                    4_i,                          // array_index
                                    5_f);                         // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevelDepth2dF32,
@@ -1535,6 +1632,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_u);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevelDepth2dOffsetF32,
@@ -1555,6 +1653,7 @@
                                    3_i,                      // level
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevelDepth2dArrayF32,
@@ -1575,6 +1674,7 @@
                                    3_u,                     // array_index
                                    4_u);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32,
@@ -1597,6 +1697,7 @@
                                    4_u,                      // level
                                    b->vec2<i32>(5_i, 6_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevelDepthCubeF32,
@@ -1615,6 +1716,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_i);                         // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleLevelDepthCubeArrayF32,
@@ -1635,6 +1737,7 @@
                                    4_i,                          // array_index
                                    5_i);                         // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleGrad2dF32,
@@ -1655,6 +1758,7 @@
                                    b->vec2<f32>(3_f, 4_f),   // ddx
                                    b->vec2<f32>(5_f, 6_f));  // ddy
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleGrad2dOffsetF32,
@@ -1677,6 +1781,7 @@
                                    b->vec2<f32>(5_f, 6_f),   // ddy
                                    b->vec2<i32>(7_i, 7_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleGrad2dArrayF32,
@@ -1699,6 +1804,7 @@
                                    b->vec2<f32>(4_f, 5_f),   // ddx
                                    b->vec2<f32>(6_f, 7_f));  // ddy
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleGrad2dArrayOffsetF32,
@@ -1723,6 +1829,7 @@
                                    b->vec2<f32>(6_f, 7_f),   // ddy
                                    b->vec2<i32>(6_i, 7_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleGrad3dF32,
@@ -1743,6 +1850,7 @@
                                    b->vec3<f32>(4_f, 5_f, 6_f),   // ddx
                                    b->vec3<f32>(7_f, 8_f, 9_f));  // ddy
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleGrad3dOffsetF32,
@@ -1765,6 +1873,7 @@
                                    b->vec3<f32>(7_f, 8_f, 9_f),   // ddy
                                    b->vec3<i32>(0_i, 1_i, 2_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleGradCubeF32,
@@ -1785,6 +1894,7 @@
                                    b->vec3<f32>(4_f, 5_f, 6_f),   // ddx
                                    b->vec3<f32>(7_f, 8_f, 9_f));  // ddy
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleGradCubeArrayF32,
@@ -1807,6 +1917,7 @@
                                    b->vec3<f32>(5_f, 6_f, 7_f),    // ddx
                                    b->vec3<f32>(8_f, 9_f, 10_f));  // ddy
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareDepth2dF32,
@@ -1825,6 +1936,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_f);                    // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareDepth2dOffsetF32,
@@ -1845,6 +1957,7 @@
                                    3_f,                      // depth_ref
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareDepth2dArrayF32,
@@ -1865,6 +1978,7 @@
                                    4_i,                     // array_index
                                    3_f);                    // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32,
@@ -1887,6 +2001,7 @@
                                    3_f,                      // depth_ref
                                    b->vec2<i32>(5_i, 6_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareDepthCubeF32,
@@ -1905,6 +2020,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_f);                         // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareDepthCubeArrayF32,
@@ -1925,6 +2041,7 @@
                                    4_i,                          // array_index
                                    5_f);                         // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareLevelDepth2dF32,
@@ -1943,6 +2060,7 @@
                                    b->vec2<f32>(1_f, 2_f),  // coords
                                    3_f);                    // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32,
@@ -1963,6 +2081,7 @@
                                    3_f,                      // depth_ref
                                    b->vec2<i32>(4_i, 5_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32,
@@ -1983,6 +2102,7 @@
                                    3_i,                     // array_index
                                    4_f);                    // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32,
@@ -2005,6 +2125,7 @@
                                    4_f,                      // depth_ref
                                    b->vec2<i32>(5_i, 6_i));  // offset
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareLevelDepthCubeF32,
@@ -2023,6 +2144,7 @@
                                    b->vec3<f32>(1_f, 2_f, 3_f),  // coords
                                    4_f);                         // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32,
@@ -2043,6 +2165,7 @@
                                    4_i,                          // array_index
                                    5_f);                         // depth_ref
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad1dLevelF32,
@@ -2058,6 +2181,7 @@
                                    1_u,           // coords
                                    3_u);          // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad1dLevelU32,
@@ -2073,6 +2197,7 @@
                                    1_i,           // coords
                                    3_i);          // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad1dLevelI32,
@@ -2088,6 +2213,7 @@
                                    1_i,           // coords
                                    3_i);          // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad2dLevelF32,
@@ -2103,6 +2229,7 @@
                                    b->vec2<u32>(1_u, 2_u),  // coords
                                    3_u);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad2dLevelU32,
@@ -2118,6 +2245,7 @@
                                    b->vec2<i32>(1_i, 2_i),  // coords
                                    3_i);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad2dLevelI32,
@@ -2133,6 +2261,7 @@
                                    b->vec2<u32>(1_u, 2_u),  // coords
                                    3_u);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad2dArrayLevelF32,
@@ -2150,6 +2279,7 @@
                                    3_i,                     // array_index
                                    4_i);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad2dArrayLevelU32,
@@ -2167,6 +2297,7 @@
                                    3_i,                     // array_index
                                    4_i);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad2dArrayLevelI32,
@@ -2184,6 +2315,7 @@
                                    3_u,                     // array_index
                                    4_u);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad3dLevelF32,
@@ -2199,6 +2331,7 @@
                                    b->vec3<i32>(1_i, 2_i, 3_i),  // coords
                                    4_i);                         // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad3dLevelU32,
@@ -2214,6 +2347,7 @@
                                    b->vec3<i32>(1_i, 2_i, 3_i),  // coords
                                    4_i);                         // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoad3dLevelI32,
@@ -2229,6 +2363,7 @@
                                    b->vec3<u32>(1_u, 2_u, 3_u),  // coords
                                    4_u);                         // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoadMultisampled2dF32,
@@ -2244,6 +2379,7 @@
                                    b->vec2<i32>(1_i, 2_i),  // coords
                                    3_i);                    // sample_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoadMultisampled2dU32,
@@ -2259,6 +2395,7 @@
                                    b->vec2<i32>(1_i, 2_i),  // coords
                                    3_i);                    // sample_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoadMultisampled2dI32,
@@ -2274,6 +2411,7 @@
                                    b->vec2<u32>(1_u, 2_u),  // coords
                                    3_u);                    // sample_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoadDepth2dLevelF32,
@@ -2289,6 +2427,7 @@
                                    b->vec2<i32>(1_i, 2_i),  // coords
                                    3_i);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoadDepth2dArrayLevelF32,
@@ -2306,6 +2445,7 @@
                                    3_u,                     // array_index
                                    4_u);                    // level
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kLoadDepthMultisampled2dF32,
@@ -2321,14 +2461,15 @@
                                    b->vec2<u32>(1_u, 2_u),  // coords
                                    3_u);                    // sample_index
             },
+            /* returns value */ true,
         },
         {
             ValidTextureOverload::kStoreWO1dRgba32float,
             "textureStore(t      : texture_storage_1d<rgba32float>,\n"
             "             coords : i32,\n"
             "             value  : vec4<T>)",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k1d,
             TextureDataType::kF32,
             "textureStore",
@@ -2337,14 +2478,15 @@
                                    1_i,                                // coords
                                    b->vec4<f32>(2_f, 3_f, 4_f, 5_f));  // value
             },
+            /* returns value */ false,
         },
         {
             ValidTextureOverload::kStoreWO2dRgba32float,
             "textureStore(t      : texture_storage_2d<rgba32float>,\n"
             "             coords : vec2<i32>,\n"
             "             value  : vec4<T>)",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k2d,
             TextureDataType::kF32,
             "textureStore",
@@ -2353,6 +2495,7 @@
                                    b->vec2<i32>(1_i, 2_i),             // coords
                                    b->vec4<f32>(3_f, 4_f, 5_f, 6_f));  // value
             },
+            /* returns value */ false,
         },
         {
             ValidTextureOverload::kStoreWO2dArrayRgba32float,
@@ -2360,8 +2503,8 @@
             "             coords      : vec2<u32>,\n"
             "             array_index : u32,\n"
             "             value       : vec4<T>)",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k2dArray,
             TextureDataType::kF32,
             "textureStore",
@@ -2371,14 +2514,15 @@
                                    3_u,                                // array_index
                                    b->vec4<f32>(4_f, 5_f, 6_f, 7_f));  // value
             },
+            /* returns value */ false,
         },
         {
             ValidTextureOverload::kStoreWO3dRgba32float,
             "textureStore(t      : texture_storage_3d<rgba32float>,\n"
             "             coords : vec3<u32>,\n"
             "             value  : vec4<T>)",
-            type::Access::kWrite,
-            type::TexelFormat::kRgba32Float,
+            tint::builtin::Access::kWrite,
+            tint::builtin::TexelFormat::kRgba32Float,
             type::TextureDimension::k3d,
             TextureDataType::kF32,
             "textureStore",
@@ -2387,6 +2531,7 @@
                                    b->vec3<u32>(1_u, 2_u, 3_u),        // coords
                                    b->vec4<f32>(4_f, 5_f, 6_f, 7_f));  // value
             },
+            /* returns value */ false,
         },
     };
 }
diff --git a/src/tint/ast/builtin_texture_helper_test.h b/src/tint/ast/builtin_texture_helper_test.h
index 6fe0193..738db0c 100644
--- a/src/tint/ast/builtin_texture_helper_test.h
+++ b/src/tint/ast/builtin_texture_helper_test.h
@@ -17,8 +17,9 @@
 
 #include <vector>
 
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/type/access.h"
 #include "src/tint/type/storage_texture.h"
 #include "src/tint/type/texture_dimension.h"
 
@@ -184,8 +185,8 @@
 
 /// Describes a texture builtin overload
 struct TextureOverloadCase {
-    /// Args is a list of ast::Expression used as arguments to the texture overload case.
-    using Args = utils::Vector<const ast::Expression*, 8>;
+    /// Args is a list of Expression used as arguments to the texture overload case.
+    using Args = utils::Vector<const Expression*, 8>;
 
     /// Constructor for textureSample...() functions
     TextureOverloadCase(ValidTextureOverload,
@@ -195,7 +196,8 @@
                         type::TextureDimension,
                         TextureDataType,
                         const char*,
-                        std::function<Args(ProgramBuilder*)>);
+                        std::function<Args(ProgramBuilder*)>,
+                        bool /* returns_value */);
     /// Constructor for textureLoad() functions with non-storage textures
     TextureOverloadCase(ValidTextureOverload,
                         const char*,
@@ -203,16 +205,18 @@
                         type::TextureDimension,
                         TextureDataType,
                         const char*,
-                        std::function<Args(ProgramBuilder*)>);
+                        std::function<Args(ProgramBuilder*)>,
+                        bool /* returns_value */);
     /// Constructor for textureLoad() with storage textures
     TextureOverloadCase(ValidTextureOverload,
                         const char*,
-                        type::Access,
-                        type::TexelFormat,
+                        tint::builtin::Access,
+                        tint::builtin::TexelFormat,
                         type::TextureDimension,
                         TextureDataType,
                         const char*,
-                        std::function<Args(ProgramBuilder*)>);
+                        std::function<Args(ProgramBuilder*)>,
+                        bool /* returns_value */);
     /// Copy constructor
     TextureOverloadCase(const TextureOverloadCase&);
     /// Destructor
@@ -224,15 +228,15 @@
 
     /// @param builder the AST builder used for the test
     /// @returns the vector component type of the texture function return value
-    ast::Type BuildResultVectorComponentType(ProgramBuilder* builder) const;
+    Type BuildResultVectorComponentType(ProgramBuilder* builder) const;
     /// @param builder the AST builder used for the test
     /// @returns a variable holding the test texture, automatically registered as
     /// a global variable.
-    const ast::Variable* BuildTextureVariable(ProgramBuilder* builder) const;
+    const Variable* BuildTextureVariable(ProgramBuilder* builder) const;
     /// @param builder the AST builder used for the test
     /// @returns a Variable holding the test sampler, automatically registered as
     /// a global variable.
-    const ast::Variable* BuildSamplerVariable(ProgramBuilder* builder) const;
+    const Variable* BuildSamplerVariable(ProgramBuilder* builder) const;
 
     /// The enumerator for this overload
     const ValidTextureOverload overload;
@@ -245,10 +249,10 @@
     type::SamplerKind const sampler_kind = type::SamplerKind::kSampler;
     /// The access control for the storage texture
     /// Used only when texture_kind is kStorage
-    type::Access const access = type::Access::kReadWrite;
+    tint::builtin::Access const access = tint::builtin::Access::kReadWrite;
     /// The image format for the storage texture
     /// Used only when texture_kind is kStorage
-    type::TexelFormat const texel_format = type::TexelFormat::kUndefined;
+    tint::builtin::TexelFormat const texel_format = tint::builtin::TexelFormat::kUndefined;
     /// The dimensions of the texture parameter
     type::TextureDimension const texture_dimension;
     /// The data type of the texture parameter
@@ -257,6 +261,8 @@
     const char* const function;
     /// A function that builds the AST arguments for the overload
     std::function<Args(ProgramBuilder*)> const args;
+    /// True if the function returns a value
+    const bool returns_value;
 };
 
 std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data);
diff --git a/src/tint/ast/call_expression.h b/src/tint/ast/call_expression.h
index b22ec11..5085818 100644
--- a/src/tint/ast/call_expression.h
+++ b/src/tint/ast/call_expression.h
@@ -27,8 +27,8 @@
 /// A call expression - represents either a:
 /// * sem::Function
 /// * sem::Builtin
-/// * sem::TypeConstructor
-/// * sem::TypeConversion
+/// * sem::ValueConstructor
+/// * sem::ValueConversion
 class CallExpression final : public Castable<CallExpression, Expression> {
   public:
     /// Constructor
diff --git a/src/tint/ast/case_selector.cc b/src/tint/ast/case_selector.cc
index 8622d3a..7419fe5 100644
--- a/src/tint/ast/case_selector.cc
+++ b/src/tint/ast/case_selector.cc
@@ -22,7 +22,7 @@
 
 namespace tint::ast {
 
-CaseSelector::CaseSelector(ProgramID pid, NodeID nid, const Source& src, const ast::Expression* e)
+CaseSelector::CaseSelector(ProgramID pid, NodeID nid, const Source& src, const Expression* e)
     : Base(pid, nid, src), expr(e) {}
 
 CaseSelector::CaseSelector(CaseSelector&&) = default;
diff --git a/src/tint/ast/diagnostic_attribute.cc b/src/tint/ast/diagnostic_attribute.cc
index 32e83d8..d93cc3a 100644
--- a/src/tint/ast/diagnostic_attribute.cc
+++ b/src/tint/ast/diagnostic_attribute.cc
@@ -26,7 +26,7 @@
 DiagnosticAttribute::DiagnosticAttribute(ProgramID pid,
                                          NodeID nid,
                                          const Source& src,
-                                         ast::DiagnosticControl&& dc)
+                                         DiagnosticControl&& dc)
     : Base(pid, nid, src), control(std::move(dc)) {}
 
 DiagnosticAttribute::~DiagnosticAttribute() = default;
diff --git a/src/tint/ast/diagnostic_attribute.h b/src/tint/ast/diagnostic_attribute.h
index 2b8cb9f..ef1fa02 100644
--- a/src/tint/ast/diagnostic_attribute.h
+++ b/src/tint/ast/diagnostic_attribute.h
@@ -30,7 +30,7 @@
     /// @param nid the unique node identifier
     /// @param src the source of this node
     /// @param dc the diagnostic control
-    DiagnosticAttribute(ProgramID pid, NodeID nid, const Source& src, ast::DiagnosticControl&& dc);
+    DiagnosticAttribute(ProgramID pid, NodeID nid, const Source& src, DiagnosticControl&& dc);
     ~DiagnosticAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -42,7 +42,7 @@
     const DiagnosticAttribute* Clone(CloneContext* ctx) const override;
 
     /// The diagnostic control.
-    const ast::DiagnosticControl control;
+    const DiagnosticControl control;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_attribute_test.cc b/src/tint/ast/diagnostic_attribute_test.cc
index 531364d..ec6ec26 100644
--- a/src/tint/ast/diagnostic_attribute_test.cc
+++ b/src/tint/ast/diagnostic_attribute_test.cc
@@ -22,9 +22,9 @@
 
 TEST_F(DiagnosticAttributeTest, Creation) {
     auto* name = Ident("foo");
-    auto* d = DiagnosticAttribute(DiagnosticSeverity::kWarning, name);
+    auto* d = DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, name);
     EXPECT_EQ(d->Name(), "diagnostic");
-    EXPECT_EQ(d->control.severity, DiagnosticSeverity::kWarning);
+    EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
     EXPECT_EQ(d->control.rule_name, name);
 }
 
diff --git a/src/tint/ast/diagnostic_control.cc b/src/tint/ast/diagnostic_control.cc
index 8fbe400..e269446 100644
--- a/src/tint/ast/diagnostic_control.cc
+++ b/src/tint/ast/diagnostic_control.cc
@@ -12,24 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/ast/diagnostic_control.cc.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #include "src/tint/ast/diagnostic_control.h"
 
 #include <string>
 
 #include "src/tint/ast/identifier.h"
 #include "src/tint/ast/templated_identifier.h"
+#include "src/tint/builtin/diagnostic_severity.h"
 
 namespace tint::ast {
 
-DiagnosticControl::DiagnosticControl(DiagnosticSeverity sev, const Identifier* rule)
+DiagnosticControl::DiagnosticControl(builtin::DiagnosticSeverity sev, const Identifier* rule)
     : severity(sev), rule_name(rule) {
     TINT_ASSERT(AST, rule != nullptr);
     if (rule) {
@@ -38,77 +31,4 @@
     }
 }
 
-diag::Severity ToSeverity(DiagnosticSeverity sc) {
-    switch (sc) {
-        case DiagnosticSeverity::kError:
-            return diag::Severity::Error;
-        case DiagnosticSeverity::kWarning:
-            return diag::Severity::Warning;
-        case DiagnosticSeverity::kInfo:
-            return diag::Severity::Note;
-        default:
-            return diag::Severity::InternalCompilerError;
-    }
-}
-
-/// ParseDiagnosticSeverity parses a DiagnosticSeverity from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or DiagnosticSeverity::kUndefined if the string could not be parsed.
-DiagnosticSeverity ParseDiagnosticSeverity(std::string_view str) {
-    if (str == "error") {
-        return DiagnosticSeverity::kError;
-    }
-    if (str == "info") {
-        return DiagnosticSeverity::kInfo;
-    }
-    if (str == "off") {
-        return DiagnosticSeverity::kOff;
-    }
-    if (str == "warning") {
-        return DiagnosticSeverity::kWarning;
-    }
-    return DiagnosticSeverity::kUndefined;
-}
-
-std::ostream& operator<<(std::ostream& out, DiagnosticSeverity value) {
-    switch (value) {
-        case DiagnosticSeverity::kUndefined:
-            return out << "undefined";
-        case DiagnosticSeverity::kError:
-            return out << "error";
-        case DiagnosticSeverity::kInfo:
-            return out << "info";
-        case DiagnosticSeverity::kOff:
-            return out << "off";
-        case DiagnosticSeverity::kWarning:
-            return out << "warning";
-    }
-    return out << "<unknown>";
-}
-
-/// ParseDiagnosticRule parses a DiagnosticRule from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or DiagnosticRule::kUndefined if the string could not be parsed.
-DiagnosticRule ParseDiagnosticRule(std::string_view str) {
-    if (str == "chromium_unreachable_code") {
-        return DiagnosticRule::kChromiumUnreachableCode;
-    }
-    if (str == "derivative_uniformity") {
-        return DiagnosticRule::kDerivativeUniformity;
-    }
-    return DiagnosticRule::kUndefined;
-}
-
-std::ostream& operator<<(std::ostream& out, DiagnosticRule value) {
-    switch (value) {
-        case DiagnosticRule::kUndefined:
-            return out << "undefined";
-        case DiagnosticRule::kChromiumUnreachableCode:
-            return out << "chromium_unreachable_code";
-        case DiagnosticRule::kDerivativeUniformity:
-            return out << "derivative_uniformity";
-    }
-    return out << "<unknown>";
-}
-
 }  // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_control.h b/src/tint/ast/diagnostic_control.h
index f4fdd5f..3a5cd1f 100644
--- a/src/tint/ast/diagnostic_control.h
+++ b/src/tint/ast/diagnostic_control.h
@@ -12,14 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/ast/diagnostic_control.h.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #ifndef SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_
 #define SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_
 
@@ -27,6 +19,7 @@
 #include <string>
 #include <unordered_map>
 
+#include "src/tint/builtin/diagnostic_severity.h"
 #include "src/tint/diagnostic/diagnostic.h"
 
 // Forward declarations
@@ -36,60 +29,6 @@
 
 namespace tint::ast {
 
-/// The diagnostic severity control.
-enum class DiagnosticSeverity {
-    kUndefined,
-    kError,
-    kInfo,
-    kOff,
-    kWarning,
-};
-
-/// @param out the std::ostream to write to
-/// @param value the DiagnosticSeverity
-/// @returns `out` so calls can be chained
-std::ostream& operator<<(std::ostream& out, DiagnosticSeverity value);
-
-/// ParseDiagnosticSeverity parses a DiagnosticSeverity from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or DiagnosticSeverity::kUndefined if the string could not be parsed.
-DiagnosticSeverity ParseDiagnosticSeverity(std::string_view str);
-
-constexpr const char* kDiagnosticSeverityStrings[] = {
-    "error",
-    "info",
-    "off",
-    "warning",
-};
-
-/// The diagnostic rule.
-enum class DiagnosticRule {
-    kUndefined,
-    kChromiumUnreachableCode,
-    kDerivativeUniformity,
-};
-
-/// @param out the std::ostream to write to
-/// @param value the DiagnosticRule
-/// @returns `out` so calls can be chained
-std::ostream& operator<<(std::ostream& out, DiagnosticRule value);
-
-/// ParseDiagnosticRule parses a DiagnosticRule from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or DiagnosticRule::kUndefined if the string could not be parsed.
-DiagnosticRule ParseDiagnosticRule(std::string_view str);
-
-constexpr const char* kDiagnosticRuleStrings[] = {
-    "chromium_unreachable_code",
-    "derivative_uniformity",
-};
-
-/// Convert a DiagnosticSeverity to the corresponding diag::Severity.
-diag::Severity ToSeverity(DiagnosticSeverity sc);
-
-/// DiagnosticRuleSeverities is a map from diagnostic rule to diagnostic severity.
-using DiagnosticRuleSeverities = std::unordered_map<DiagnosticRule, DiagnosticSeverity>;
-
 /// A diagnostic control used for diagnostic directives and attributes.
 struct DiagnosticControl {
   public:
@@ -99,10 +38,10 @@
     /// Constructor
     /// @param sev the diagnostic severity
     /// @param rule the diagnostic rule name
-    DiagnosticControl(DiagnosticSeverity sev, const Identifier* rule);
+    DiagnosticControl(builtin::DiagnosticSeverity sev, const Identifier* rule);
 
     /// The diagnostic severity control.
-    DiagnosticSeverity severity;
+    builtin::DiagnosticSeverity severity;
 
     /// The diagnostic rule name.
     const Identifier* rule_name;
diff --git a/src/tint/ast/diagnostic_control.h.tmpl b/src/tint/ast/diagnostic_control.h.tmpl
deleted file mode 100644
index 4645d9c..0000000
--- a/src/tint/ast/diagnostic_control.h.tmpl
+++ /dev/null
@@ -1,61 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate diagnostic_control.h
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- Import "src/tint/templates/enums.tmpl.inc" -}}
-
-#ifndef SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_
-#define SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_
-
-#include <ostream>
-#include <string>
-#include <unordered_map>
-
-#include "src/tint/diagnostic/diagnostic.h"
-
-// Forward declarations
-namespace tint::ast {
-class Identifier;
-}  // namespace tint::ast
-
-namespace tint::ast {
-
-/// The diagnostic severity control.
-{{ Eval "DeclareEnum" (Sem.Enum "diagnostic_severity") }}
-
-/// The diagnostic rule.
-{{ Eval "DeclareEnum" (Sem.Enum "diagnostic_rule") }}
-
-/// Convert a DiagnosticSeverity to the corresponding diag::Severity.
-diag::Severity ToSeverity(DiagnosticSeverity sc);
-
-/// DiagnosticRuleSeverities is a map from diagnostic rule to diagnostic severity.
-using DiagnosticRuleSeverities = std::unordered_map<DiagnosticRule, DiagnosticSeverity>;
-
-/// A diagnostic control used for diagnostic directives and attributes.
-struct DiagnosticControl {
-  public:
-    /// Default constructor.
-    DiagnosticControl() {}
-
-    /// Constructor
-    /// @param sev the diagnostic severity
-    /// @param rule the diagnostic rule name
-    DiagnosticControl(DiagnosticSeverity sev, const Identifier* rule);
-
-    /// The diagnostic severity control.
-    DiagnosticSeverity severity;
-
-    /// The diagnostic rule name.
-    const Identifier* rule_name;
-};
-
-}  // namespace tint::ast
-
-#endif  // SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_
diff --git a/src/tint/ast/diagnostic_control_test.cc b/src/tint/ast/diagnostic_control_test.cc
index 73046ce..53afe53 100644
--- a/src/tint/ast/diagnostic_control_test.cc
+++ b/src/tint/ast/diagnostic_control_test.cc
@@ -12,19 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/ast/diagnostic_control_test.cc.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #include <string>
 
 #include "gtest/gtest-spi.h"
 #include "src/tint/ast/diagnostic_control.h"
 #include "src/tint/ast/test_helper.h"
+#include "src/tint/builtin/diagnostic_severity.h"
 
 namespace tint::ast {
 namespace {
@@ -35,119 +28,11 @@
     EXPECT_FATAL_FAILURE(
         {
             ProgramBuilder b;
-            ast::DiagnosticControl control(DiagnosticSeverity::kWarning,
-                                           b.Ident("name", "a", "b", "c"));
+            DiagnosticControl control(builtin::DiagnosticSeverity::kWarning,
+                                      b.Ident("name", "a", "b", "c"));
         },
         "internal compiler error");
 }
 
-namespace diagnostic_severity_tests {
-
-namespace parse_print_tests {
-
-struct Case {
-    const char* string;
-    DiagnosticSeverity value;
-};
-
-inline std::ostream& operator<<(std::ostream& out, Case c) {
-    return out << "'" << std::string(c.string) << "'";
-}
-
-static constexpr Case kValidCases[] = {
-    {"error", DiagnosticSeverity::kError},
-    {"info", DiagnosticSeverity::kInfo},
-    {"off", DiagnosticSeverity::kOff},
-    {"warning", DiagnosticSeverity::kWarning},
-};
-
-static constexpr Case kInvalidCases[] = {
-    {"erccr", DiagnosticSeverity::kUndefined},    {"3o", DiagnosticSeverity::kUndefined},
-    {"eVror", DiagnosticSeverity::kUndefined},    {"1nfo", DiagnosticSeverity::kUndefined},
-    {"iqfJ", DiagnosticSeverity::kUndefined},     {"illf77", DiagnosticSeverity::kUndefined},
-    {"oppqH", DiagnosticSeverity::kUndefined},    {"", DiagnosticSeverity::kUndefined},
-    {"Gb", DiagnosticSeverity::kUndefined},       {"warniivg", DiagnosticSeverity::kUndefined},
-    {"8WWrning", DiagnosticSeverity::kUndefined}, {"wxxning", DiagnosticSeverity::kUndefined},
-};
-
-using DiagnosticSeverityParseTest = testing::TestWithParam<Case>;
-
-TEST_P(DiagnosticSeverityParseTest, Parse) {
-    const char* string = GetParam().string;
-    DiagnosticSeverity expect = GetParam().value;
-    EXPECT_EQ(expect, ParseDiagnosticSeverity(string));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticSeverityParseTest, testing::ValuesIn(kValidCases));
-INSTANTIATE_TEST_SUITE_P(InvalidCases,
-                         DiagnosticSeverityParseTest,
-                         testing::ValuesIn(kInvalidCases));
-
-using DiagnosticSeverityPrintTest = testing::TestWithParam<Case>;
-
-TEST_P(DiagnosticSeverityPrintTest, Print) {
-    DiagnosticSeverity value = GetParam().value;
-    const char* expect = GetParam().string;
-    EXPECT_EQ(expect, utils::ToString(value));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticSeverityPrintTest, testing::ValuesIn(kValidCases));
-
-}  // namespace parse_print_tests
-
-}  // namespace diagnostic_severity_tests
-
-namespace diagnostic_rule_tests {
-
-namespace parse_print_tests {
-
-struct Case {
-    const char* string;
-    DiagnosticRule value;
-};
-
-inline std::ostream& operator<<(std::ostream& out, Case c) {
-    return out << "'" << std::string(c.string) << "'";
-}
-
-static constexpr Case kValidCases[] = {
-    {"chromium_unreachable_code", DiagnosticRule::kChromiumUnreachableCode},
-    {"derivative_uniformity", DiagnosticRule::kDerivativeUniformity},
-};
-
-static constexpr Case kInvalidCases[] = {
-    {"cXromggum_unreachable_cde", DiagnosticRule::kUndefined},
-    {"chroVium_unruchble_codX", DiagnosticRule::kUndefined},
-    {"chromium_3nreachable_code", DiagnosticRule::kUndefined},
-    {"derivatEve_uniformity", DiagnosticRule::kUndefined},
-    {"deTTPivative_uniformit", DiagnosticRule::kUndefined},
-    {"derivtive_uddxxformity", DiagnosticRule::kUndefined},
-};
-
-using DiagnosticRuleParseTest = testing::TestWithParam<Case>;
-
-TEST_P(DiagnosticRuleParseTest, Parse) {
-    const char* string = GetParam().string;
-    DiagnosticRule expect = GetParam().value;
-    EXPECT_EQ(expect, ParseDiagnosticRule(string));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticRuleParseTest, testing::ValuesIn(kValidCases));
-INSTANTIATE_TEST_SUITE_P(InvalidCases, DiagnosticRuleParseTest, testing::ValuesIn(kInvalidCases));
-
-using DiagnosticRulePrintTest = testing::TestWithParam<Case>;
-
-TEST_P(DiagnosticRulePrintTest, Print) {
-    DiagnosticRule value = GetParam().value;
-    const char* expect = GetParam().string;
-    EXPECT_EQ(expect, utils::ToString(value));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticRulePrintTest, testing::ValuesIn(kValidCases));
-
-}  // namespace parse_print_tests
-
-}  // namespace diagnostic_rule_tests
-
 }  // namespace
 }  // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_control_test.cc.tmpl b/src/tint/ast/diagnostic_control_test.cc.tmpl
deleted file mode 100644
index 9900556..0000000
--- a/src/tint/ast/diagnostic_control_test.cc.tmpl
+++ /dev/null
@@ -1,47 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate diagnostic_control_test.cc
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- Import "src/tint/templates/enums.tmpl.inc" -}}
-
-#include <string>
-
-#include "gtest/gtest-spi.h"
-#include "src/tint/ast/diagnostic_control.h"
-#include "src/tint/ast/test_helper.h"
-
-namespace tint::ast {
-namespace {
-
-using DiagnosticControlTest = TestHelper;
-
-TEST_F(DiagnosticControlTest, Assert_RuleNotTemplated) {
-    EXPECT_FATAL_FAILURE(
-        {
-            ProgramBuilder b;
-            ast::DiagnosticControl control(DiagnosticSeverity::kWarning,
-                                           b.Ident("name", "a", "b", "c"));
-        },
-        "internal compiler error");
-}
-
-namespace diagnostic_severity_tests {
-
-{{ Eval "TestParsePrintEnum" (Sem.Enum "diagnostic_severity")}}
-
-}  // namespace diagnostic_severity_tests
-
-namespace diagnostic_rule_tests {
-
-{{ Eval "TestParsePrintEnum" (Sem.Enum "diagnostic_rule")}}
-
-}  // namespace diagnostic_rule_tests
-
-}  // namespace
-}  // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_directive_test.cc b/src/tint/ast/diagnostic_directive_test.cc
index fb88439..3e23d6a 100644
--- a/src/tint/ast/diagnostic_directive_test.cc
+++ b/src/tint/ast/diagnostic_directive_test.cc
@@ -22,15 +22,14 @@
 using DiagnosticDirectiveTest = TestHelper;
 
 TEST_F(DiagnosticDirectiveTest, Creation) {
-    auto* name = Ident("foo");
-    DiagnosticControl control(ast::DiagnosticSeverity::kWarning, name);
-    auto* diag = create<ast::DiagnosticDirective>(Source{{{10, 5}, {10, 15}}}, std::move(control));
+    auto* diag = DiagnosticDirective(Source{{{10, 5}, {10, 15}}},
+                                     builtin::DiagnosticSeverity::kWarning, "foo");
     EXPECT_EQ(diag->source.range.begin.line, 10u);
     EXPECT_EQ(diag->source.range.begin.column, 5u);
     EXPECT_EQ(diag->source.range.end.line, 10u);
     EXPECT_EQ(diag->source.range.end.column, 15u);
-    EXPECT_EQ(diag->control.severity, ast::DiagnosticSeverity::kWarning);
-    EXPECT_EQ(diag->control.rule_name, name);
+    EXPECT_EQ(diag->control.severity, builtin::DiagnosticSeverity::kWarning);
+    CheckIdentifier(Symbols(), diag->control.rule_name, "foo");
 }
 
 }  // namespace
diff --git a/src/tint/ast/disable_validation_attribute.cc b/src/tint/ast/disable_validation_attribute.cc
index 465a0ec..eff1c1f 100644
--- a/src/tint/ast/disable_validation_attribute.cc
+++ b/src/tint/ast/disable_validation_attribute.cc
@@ -45,6 +45,8 @@
             return "disable_validation__ignore_invalid_pointer_argument";
         case DisabledValidation::kIgnorePointerAliasing:
             return "disable_validation__ignore_pointer_aliasing";
+        case DisabledValidation::kIgnoreStructMemberLimit:
+            return "disable_validation__ignore_struct_member";
     }
     return "<invalid>";
 }
diff --git a/src/tint/ast/disable_validation_attribute.h b/src/tint/ast/disable_validation_attribute.h
index f52b107..9614bc1 100644
--- a/src/tint/ast/disable_validation_attribute.h
+++ b/src/tint/ast/disable_validation_attribute.h
@@ -45,6 +45,8 @@
     /// When applied to a function declaration, the validator will not complain if multiple
     /// pointer arguments alias when that function is called.
     kIgnorePointerAliasing,
+    /// When applied to a struct, validation of max number of members is skipped.
+    kIgnoreStructMemberLimit,
 };
 
 /// An internal attribute used to tell the validator to ignore specific
diff --git a/src/tint/ast/enable_test.cc b/src/tint/ast/enable_test.cc
index 9215018..5622207 100644
--- a/src/tint/ast/enable_test.cc
+++ b/src/tint/ast/enable_test.cc
@@ -22,7 +22,7 @@
 using EnableTest = TestHelper;
 
 TEST_F(EnableTest, Creation) {
-    auto* ext = create<ast::Enable>(Source{{{20, 2}, {20, 5}}}, builtin::Extension::kF16);
+    auto* ext = Enable(Source{{{20, 2}, {20, 5}}}, builtin::Extension::kF16);
     EXPECT_EQ(ext->source.range.begin.line, 20u);
     EXPECT_EQ(ext->source.range.begin.column, 2u);
     EXPECT_EQ(ext->source.range.end.line, 20u);
diff --git a/src/tint/ast/function.h b/src/tint/ast/function.h
index 802f46d..dc8cc70 100644
--- a/src/tint/ast/function.h
+++ b/src/tint/ast/function.h
@@ -68,7 +68,7 @@
     ast::PipelineStage PipelineStage() const;
 
     /// @returns true if this function is an entry point
-    bool IsEntryPoint() const { return PipelineStage() != PipelineStage::kNone; }
+    bool IsEntryPoint() const { return PipelineStage() != ast::PipelineStage::kNone; }
 
     /// Clones this node and all transitive child nodes using the `CloneContext`
     /// `ctx`.
@@ -111,12 +111,12 @@
     /// @param sym the function symbol to search for
     /// @param stage the pipeline stage
     /// @returns the associated function or nullptr if none exists
-    const Function* Find(Symbol sym, PipelineStage stage) const;
+    const Function* Find(Symbol sym, ast::PipelineStage stage) const;
 
     /// @param stage the pipeline stage
     /// @returns true if the Builder contains an entrypoint function with
     /// the given stage
-    bool HasStage(PipelineStage stage) const;
+    bool HasStage(ast::PipelineStage stage) const;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/function_test.cc b/src/tint/ast/function_test.cc
index a9b327e..1af27a6 100644
--- a/src/tint/ast/function_test.cc
+++ b/src/tint/ast/function_test.cc
@@ -65,23 +65,23 @@
     auto* f = Func("func", utils::Empty, ty.void_(), utils::Vector{Discard(), Return()});
     ASSERT_NE(f->body, nullptr);
     ASSERT_EQ(f->body->statements.Length(), 2u);
-    EXPECT_TRUE(f->body->statements[0]->Is<ast::DiscardStatement>());
-    EXPECT_TRUE(f->body->statements[1]->Is<ast::ReturnStatement>());
+    EXPECT_TRUE(f->body->statements[0]->Is<DiscardStatement>());
+    EXPECT_TRUE(f->body->statements[1]->Is<ReturnStatement>());
 }
 
 TEST_F(FunctionTest, Creation_Body_Block) {
     auto* f = Func("func", utils::Empty, ty.void_(), Block(Discard(), Return()));
     ASSERT_NE(f->body, nullptr);
     ASSERT_EQ(f->body->statements.Length(), 2u);
-    EXPECT_TRUE(f->body->statements[0]->Is<ast::DiscardStatement>());
-    EXPECT_TRUE(f->body->statements[1]->Is<ast::ReturnStatement>());
+    EXPECT_TRUE(f->body->statements[0]->Is<DiscardStatement>());
+    EXPECT_TRUE(f->body->statements[1]->Is<ReturnStatement>());
 }
 
 TEST_F(FunctionTest, Creation_Body_Stmt) {
     auto* f = Func("func", utils::Empty, ty.void_(), Return());
     ASSERT_NE(f->body, nullptr);
     ASSERT_EQ(f->body->statements.Length(), 1u);
-    EXPECT_TRUE(f->body->statements[0]->Is<ast::ReturnStatement>());
+    EXPECT_TRUE(f->body->statements[0]->Is<ReturnStatement>());
 }
 
 TEST_F(FunctionTest, Creation_Body_Nullptr) {
@@ -117,7 +117,7 @@
 }
 
 TEST_F(FunctionTest, Assert_NullParam) {
-    using ParamList = utils::Vector<const ast::Parameter*, 2>;
+    using ParamList = utils::Vector<const Parameter*, 2>;
     EXPECT_FATAL_FAILURE(
         {
             ProgramBuilder b;
diff --git a/src/tint/ast/group_attribute.cc b/src/tint/ast/group_attribute.cc
index ff60bd5..9c1952c 100644
--- a/src/tint/ast/group_attribute.cc
+++ b/src/tint/ast/group_attribute.cc
@@ -22,10 +22,7 @@
 
 namespace tint::ast {
 
-GroupAttribute::GroupAttribute(ProgramID pid,
-                               NodeID nid,
-                               const Source& src,
-                               const ast::Expression* exp)
+GroupAttribute::GroupAttribute(ProgramID pid, NodeID nid, const Source& src, const Expression* exp)
     : Base(pid, nid, src), expr(exp) {}
 
 GroupAttribute::~GroupAttribute() = default;
diff --git a/src/tint/ast/group_attribute.h b/src/tint/ast/group_attribute.h
index 552a69f..af57eb5 100644
--- a/src/tint/ast/group_attribute.h
+++ b/src/tint/ast/group_attribute.h
@@ -30,7 +30,7 @@
     /// @param nid the unique node identifier
     /// @param src the source of this node
     /// @param expr the group expression
-    GroupAttribute(ProgramID pid, NodeID nid, const Source& src, const ast::Expression* expr);
+    GroupAttribute(ProgramID pid, NodeID nid, const Source& src, const Expression* expr);
     ~GroupAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -43,7 +43,7 @@
     const GroupAttribute* Clone(CloneContext* ctx) const override;
 
     /// The group expression
-    const ast::Expression* const expr;
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/id_attribute.cc b/src/tint/ast/id_attribute.cc
index 0515f01..b056773 100644
--- a/src/tint/ast/id_attribute.cc
+++ b/src/tint/ast/id_attribute.cc
@@ -22,7 +22,7 @@
 
 namespace tint::ast {
 
-IdAttribute::IdAttribute(ProgramID pid, NodeID nid, const Source& src, const ast::Expression* exp)
+IdAttribute::IdAttribute(ProgramID pid, NodeID nid, const Source& src, const Expression* exp)
     : Base(pid, nid, src), expr(exp) {}
 
 IdAttribute::~IdAttribute() = default;
diff --git a/src/tint/ast/id_attribute.h b/src/tint/ast/id_attribute.h
index f683080..5557a06 100644
--- a/src/tint/ast/id_attribute.h
+++ b/src/tint/ast/id_attribute.h
@@ -30,7 +30,7 @@
     /// @param nid the unique node identifier
     /// @param src the source of this node
     /// @param expr the numeric id expression
-    IdAttribute(ProgramID pid, NodeID nid, const Source& src, const ast::Expression* expr);
+    IdAttribute(ProgramID pid, NodeID nid, const Source& src, const Expression* expr);
     ~IdAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -43,7 +43,7 @@
     const IdAttribute* Clone(CloneContext* ctx) const override;
 
     /// The id expression
-    const ast::Expression* const expr;
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/id_attribute_test.cc b/src/tint/ast/id_attribute_test.cc
index eeef23b..7541a1d 100644
--- a/src/tint/ast/id_attribute_test.cc
+++ b/src/tint/ast/id_attribute_test.cc
@@ -24,7 +24,7 @@
 
 TEST_F(IdAttributeTest, Creation) {
     auto* d = Id(12_a);
-    EXPECT_TRUE(d->expr->Is<ast::IntLiteralExpression>());
+    EXPECT_TRUE(d->expr->Is<IntLiteralExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/ast/identifier.h b/src/tint/ast/identifier.h
index 0d99b00..7160173 100644
--- a/src/tint/ast/identifier.h
+++ b/src/tint/ast/identifier.h
@@ -20,7 +20,7 @@
 namespace tint::ast {
 
 /// An identifier
-class Identifier : public Castable<Identifier, ast::Node> {
+class Identifier : public Castable<Identifier, Node> {
   public:
     /// Constructor
     /// @param pid the identifier of the program that owns this node
diff --git a/src/tint/ast/identifier_expression_test.cc b/src/tint/ast/identifier_expression_test.cc
index e31b654..0e0e7c0 100644
--- a/src/tint/ast/identifier_expression_test.cc
+++ b/src/tint/ast/identifier_expression_test.cc
@@ -30,10 +30,10 @@
 TEST_F(IdentifierExpressionTest, CreationTemplated) {
     auto* i = Expr(Ident("ident", true));
     EXPECT_EQ(i->identifier->symbol, Symbol(1, ID()));
-    auto* tmpl_ident = i->identifier->As<ast::TemplatedIdentifier>();
+    auto* tmpl_ident = i->identifier->As<TemplatedIdentifier>();
     ASSERT_NE(tmpl_ident, nullptr);
     EXPECT_EQ(tmpl_ident->arguments.Length(), 1_u);
-    EXPECT_TRUE(tmpl_ident->arguments[0]->Is<ast::BoolLiteralExpression>());
+    EXPECT_TRUE(tmpl_ident->arguments[0]->Is<BoolLiteralExpression>());
 }
 
 TEST_F(IdentifierExpressionTest, Creation_WithSource) {
diff --git a/src/tint/ast/if_statement.cc b/src/tint/ast/if_statement.cc
index 5f7f1a7..fdea1da 100644
--- a/src/tint/ast/if_statement.cc
+++ b/src/tint/ast/if_statement.cc
@@ -33,7 +33,7 @@
     TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
     if (else_statement) {
         TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, else_statement, program_id);
-        TINT_ASSERT(AST, (else_statement->IsAnyOf<ast::IfStatement, ast::BlockStatement>()));
+        TINT_ASSERT(AST, (else_statement->IsAnyOf<IfStatement, BlockStatement>()));
     }
 }
 
diff --git a/src/tint/ast/interpolate_attribute.cc b/src/tint/ast/interpolate_attribute.cc
index 2e9ef2a..eda6405 100644
--- a/src/tint/ast/interpolate_attribute.cc
+++ b/src/tint/ast/interpolate_attribute.cc
@@ -12,14 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/ast/interpolate_attribute.cc.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #include "src/tint/ast/interpolate_attribute.h"
 
 #include <string>
@@ -33,8 +25,8 @@
 InterpolateAttribute::InterpolateAttribute(ProgramID pid,
                                            NodeID nid,
                                            const Source& src,
-                                           InterpolationType ty,
-                                           InterpolationSampling smpl)
+                                           const Expression* ty,
+                                           const Expression* smpl)
     : Base(pid, nid, src), type(ty), sampling(smpl) {}
 
 InterpolateAttribute::~InterpolateAttribute() = default;
@@ -46,68 +38,9 @@
 const InterpolateAttribute* InterpolateAttribute::Clone(CloneContext* ctx) const {
     // Clone arguments outside of create() call to have deterministic ordering
     auto src = ctx->Clone(source);
-    return ctx->dst->create<InterpolateAttribute>(src, type, sampling);
-}
-
-/// ParseInterpolationType parses a InterpolationType from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or InterpolationType::kUndefined if the string could not be parsed.
-InterpolationType ParseInterpolationType(std::string_view str) {
-    if (str == "flat") {
-        return InterpolationType::kFlat;
-    }
-    if (str == "linear") {
-        return InterpolationType::kLinear;
-    }
-    if (str == "perspective") {
-        return InterpolationType::kPerspective;
-    }
-    return InterpolationType::kUndefined;
-}
-
-std::ostream& operator<<(std::ostream& out, InterpolationType value) {
-    switch (value) {
-        case InterpolationType::kUndefined:
-            return out << "undefined";
-        case InterpolationType::kFlat:
-            return out << "flat";
-        case InterpolationType::kLinear:
-            return out << "linear";
-        case InterpolationType::kPerspective:
-            return out << "perspective";
-    }
-    return out << "<unknown>";
-}
-
-/// ParseInterpolationSampling parses a InterpolationSampling from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or InterpolationSampling::kUndefined if the string could not be
-/// parsed.
-InterpolationSampling ParseInterpolationSampling(std::string_view str) {
-    if (str == "center") {
-        return InterpolationSampling::kCenter;
-    }
-    if (str == "centroid") {
-        return InterpolationSampling::kCentroid;
-    }
-    if (str == "sample") {
-        return InterpolationSampling::kSample;
-    }
-    return InterpolationSampling::kUndefined;
-}
-
-std::ostream& operator<<(std::ostream& out, InterpolationSampling value) {
-    switch (value) {
-        case InterpolationSampling::kUndefined:
-            return out << "undefined";
-        case InterpolationSampling::kCenter:
-            return out << "center";
-        case InterpolationSampling::kCentroid:
-            return out << "centroid";
-        case InterpolationSampling::kSample:
-            return out << "sample";
-    }
-    return out << "<unknown>";
+    auto* ty = ctx->Clone(type);
+    auto* smpl = ctx->Clone(sampling);
+    return ctx->dst->create<InterpolateAttribute>(src, ty, smpl);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute.cc.tmpl b/src/tint/ast/interpolate_attribute.cc.tmpl
deleted file mode 100644
index b6f0b35..0000000
--- a/src/tint/ast/interpolate_attribute.cc.tmpl
+++ /dev/null
@@ -1,50 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate builtin_value.cc
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- Import "src/tint/templates/enums.tmpl.inc" -}}
-
-#include "src/tint/ast/interpolate_attribute.h"
-
-#include <string>
-
-#include "src/tint/program_builder.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::ast::InterpolateAttribute);
-
-namespace tint::ast {
-
-InterpolateAttribute::InterpolateAttribute(ProgramID pid,
-                                           NodeID nid,
-                                           const Source& src,
-                                           InterpolationType ty,
-                                           InterpolationSampling smpl)
-    : Base(pid, nid, src), type(ty), sampling(smpl) {}
-
-InterpolateAttribute::~InterpolateAttribute() = default;
-
-std::string InterpolateAttribute::Name() const {
-    return "interpolate";
-}
-
-const InterpolateAttribute* InterpolateAttribute::Clone(CloneContext* ctx) const {
-    // Clone arguments outside of create() call to have deterministic ordering
-    auto src = ctx->Clone(source);
-    return ctx->dst->create<InterpolateAttribute>(src, type, sampling);
-}
-
-{{ Eval "ParseEnum" (Sem.Enum "interpolation_type")}}
-
-{{ Eval "EnumOStream" (Sem.Enum "interpolation_type")}}
-
-{{ Eval "ParseEnum" (Sem.Enum "interpolation_sampling")}}
-
-{{ Eval "EnumOStream" (Sem.Enum "interpolation_sampling")}}
-
-}  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute.h b/src/tint/ast/interpolate_attribute.h
index dd60156..e50d8dd 100644
--- a/src/tint/ast/interpolate_attribute.h
+++ b/src/tint/ast/interpolate_attribute.h
@@ -12,14 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/ast/interpolate_attribute.h.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #ifndef SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
 #define SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
 
@@ -28,56 +20,12 @@
 
 #include "src/tint/ast/attribute.h"
 
+// Forward declarations
 namespace tint::ast {
+class Expression;
+}
 
-/// The interpolation type.
-enum class InterpolationType {
-    kUndefined,
-    kFlat,
-    kLinear,
-    kPerspective,
-};
-
-/// @param out the std::ostream to write to
-/// @param value the InterpolationType
-/// @returns `out` so calls can be chained
-std::ostream& operator<<(std::ostream& out, InterpolationType value);
-
-/// ParseInterpolationType parses a InterpolationType from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or InterpolationType::kUndefined if the string could not be parsed.
-InterpolationType ParseInterpolationType(std::string_view str);
-
-constexpr const char* kInterpolationTypeStrings[] = {
-    "flat",
-    "linear",
-    "perspective",
-};
-
-/// The interpolation sampling.
-enum class InterpolationSampling {
-    kUndefined,
-    kCenter,
-    kCentroid,
-    kSample,
-};
-
-/// @param out the std::ostream to write to
-/// @param value the InterpolationSampling
-/// @returns `out` so calls can be chained
-std::ostream& operator<<(std::ostream& out, InterpolationSampling value);
-
-/// ParseInterpolationSampling parses a InterpolationSampling from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or InterpolationSampling::kUndefined if the string could not be
-/// parsed.
-InterpolationSampling ParseInterpolationSampling(std::string_view str);
-
-constexpr const char* kInterpolationSamplingStrings[] = {
-    "center",
-    "centroid",
-    "sample",
-};
+namespace tint::ast {
 
 /// An interpolate attribute
 class InterpolateAttribute final : public Castable<InterpolateAttribute, Attribute> {
@@ -91,8 +39,8 @@
     InterpolateAttribute(ProgramID pid,
                          NodeID nid,
                          const Source& src,
-                         InterpolationType type,
-                         InterpolationSampling sampling);
+                         const Expression* type,
+                         const Expression* sampling);
     ~InterpolateAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -105,10 +53,10 @@
     const InterpolateAttribute* Clone(CloneContext* ctx) const override;
 
     /// The interpolation type
-    const InterpolationType type;
+    const Expression* const type;
 
     /// The interpolation sampling
-    const InterpolationSampling sampling;
+    const Expression* const sampling;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute.h.tmpl b/src/tint/ast/interpolate_attribute.h.tmpl
deleted file mode 100644
index c225cb6..0000000
--- a/src/tint/ast/interpolate_attribute.h.tmpl
+++ /dev/null
@@ -1,63 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate interpolate_attribute.h
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- Import "src/tint/templates/enums.tmpl.inc" -}}
-
-#ifndef SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
-#define SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
-
-#include <ostream>
-#include <string>
-
-#include "src/tint/ast/attribute.h"
-
-namespace tint::ast {
-
-/// The interpolation type.
-{{ Eval "DeclareEnum" (Sem.Enum "interpolation_type") }}
-
-/// The interpolation sampling.
-{{ Eval "DeclareEnum" (Sem.Enum "interpolation_sampling") }}
-
-/// An interpolate attribute
-class InterpolateAttribute final : public Castable<InterpolateAttribute, Attribute> {
-  public:
-    /// Create an interpolate attribute.
-    /// @param pid the identifier of the program that owns this node
-    /// @param nid the unique node identifier
-    /// @param src the source of this node
-    /// @param type the interpolation type
-    /// @param sampling the interpolation sampling
-    InterpolateAttribute(ProgramID pid,
-                         NodeID nid,
-                         const Source& src,
-                         InterpolationType type,
-                         InterpolationSampling sampling);
-    ~InterpolateAttribute() override;
-
-    /// @returns the WGSL name for the attribute
-    std::string Name() const override;
-
-    /// Clones this node and all transitive child nodes using the `CloneContext`
-    /// `ctx`.
-    /// @param ctx the clone context
-    /// @return the newly cloned node
-    const InterpolateAttribute* Clone(CloneContext* ctx) const override;
-
-    /// The interpolation type
-    const InterpolationType type;
-
-    /// The interpolation sampling
-    const InterpolationSampling sampling;
-};
-
-}  // namespace tint::ast
-
-#endif  // SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
diff --git a/src/tint/ast/interpolate_attribute_test.cc b/src/tint/ast/interpolate_attribute_test.cc
index 6c1204f..ecb2fac 100644
--- a/src/tint/ast/interpolate_attribute_test.cc
+++ b/src/tint/ast/interpolate_attribute_test.cc
@@ -12,14 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/ast/interpolate_attribute_test.cc.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #include "src/tint/ast/interpolate_attribute.h"
 
 #include <string>
@@ -34,122 +26,10 @@
 
 TEST_F(InterpolateAttributeTest, Creation) {
     auto* d =
-        create<InterpolateAttribute>(InterpolationType::kLinear, InterpolationSampling::kCenter);
-    EXPECT_EQ(InterpolationType::kLinear, d->type);
-    EXPECT_EQ(InterpolationSampling::kCenter, d->sampling);
+        Interpolate(builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCenter);
+    CheckIdentifier(Symbols(), d->type, "linear");
+    CheckIdentifier(Symbols(), d->sampling, "center");
 }
 
-namespace interpolation_type_tests {
-
-namespace parse_print_tests {
-
-struct Case {
-    const char* string;
-    InterpolationType value;
-};
-
-inline std::ostream& operator<<(std::ostream& out, Case c) {
-    return out << "'" << std::string(c.string) << "'";
-}
-
-static constexpr Case kValidCases[] = {
-    {"flat", InterpolationType::kFlat},
-    {"linear", InterpolationType::kLinear},
-    {"perspective", InterpolationType::kPerspective},
-};
-
-static constexpr Case kInvalidCases[] = {
-    {"ccat", InterpolationType::kUndefined},          {"3", InterpolationType::kUndefined},
-    {"fVat", InterpolationType::kUndefined},          {"1inear", InterpolationType::kUndefined},
-    {"lnqqar", InterpolationType::kUndefined},        {"linell77", InterpolationType::kUndefined},
-    {"perppHqective", InterpolationType::kUndefined}, {"cespctve", InterpolationType::kUndefined},
-    {"ebGpective", InterpolationType::kUndefined},
-};
-
-using InterpolationTypeParseTest = testing::TestWithParam<Case>;
-
-TEST_P(InterpolationTypeParseTest, Parse) {
-    const char* string = GetParam().string;
-    InterpolationType expect = GetParam().value;
-    EXPECT_EQ(expect, ParseInterpolationType(string));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypeParseTest, testing::ValuesIn(kValidCases));
-INSTANTIATE_TEST_SUITE_P(InvalidCases,
-                         InterpolationTypeParseTest,
-                         testing::ValuesIn(kInvalidCases));
-
-using InterpolationTypePrintTest = testing::TestWithParam<Case>;
-
-TEST_P(InterpolationTypePrintTest, Print) {
-    InterpolationType value = GetParam().value;
-    const char* expect = GetParam().string;
-    EXPECT_EQ(expect, utils::ToString(value));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypePrintTest, testing::ValuesIn(kValidCases));
-
-}  // namespace parse_print_tests
-
-}  // namespace interpolation_type_tests
-
-namespace interpolation_sampling_tests {
-
-namespace parse_print_tests {
-
-struct Case {
-    const char* string;
-    InterpolationSampling value;
-};
-
-inline std::ostream& operator<<(std::ostream& out, Case c) {
-    return out << "'" << std::string(c.string) << "'";
-}
-
-static constexpr Case kValidCases[] = {
-    {"center", InterpolationSampling::kCenter},
-    {"centroid", InterpolationSampling::kCentroid},
-    {"sample", InterpolationSampling::kSample},
-};
-
-static constexpr Case kInvalidCases[] = {
-    {"cevteii", InterpolationSampling::kUndefined}, {"ceWWt8r", InterpolationSampling::kUndefined},
-    {"xxentr", InterpolationSampling::kUndefined},  {"ceXggrid", InterpolationSampling::kUndefined},
-    {"ceXriu", InterpolationSampling::kUndefined},  {"centr3id", InterpolationSampling::kUndefined},
-    {"sEmple", InterpolationSampling::kUndefined},  {"amTTlPP", InterpolationSampling::kUndefined},
-    {"ddamxxl", InterpolationSampling::kUndefined},
-};
-
-using InterpolationSamplingParseTest = testing::TestWithParam<Case>;
-
-TEST_P(InterpolationSamplingParseTest, Parse) {
-    const char* string = GetParam().string;
-    InterpolationSampling expect = GetParam().value;
-    EXPECT_EQ(expect, ParseInterpolationSampling(string));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases,
-                         InterpolationSamplingParseTest,
-                         testing::ValuesIn(kValidCases));
-INSTANTIATE_TEST_SUITE_P(InvalidCases,
-                         InterpolationSamplingParseTest,
-                         testing::ValuesIn(kInvalidCases));
-
-using InterpolationSamplingPrintTest = testing::TestWithParam<Case>;
-
-TEST_P(InterpolationSamplingPrintTest, Print) {
-    InterpolationSampling value = GetParam().value;
-    const char* expect = GetParam().string;
-    EXPECT_EQ(expect, utils::ToString(value));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases,
-                         InterpolationSamplingPrintTest,
-                         testing::ValuesIn(kValidCases));
-
-}  // namespace parse_print_tests
-
-}  // namespace interpolation_sampling_tests
-
 }  // namespace
 }  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute_test.cc.tmpl b/src/tint/ast/interpolate_attribute_test.cc.tmpl
deleted file mode 100644
index 1adc9ab..0000000
--- a/src/tint/ast/interpolate_attribute_test.cc.tmpl
+++ /dev/null
@@ -1,45 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate interpolate_attribute_test.cc
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- Import "src/tint/templates/enums.tmpl.inc" -}}
-
-#include "src/tint/ast/interpolate_attribute.h"
-
-#include <string>
-
-#include "src/tint/ast/test_helper.h"
-#include "src/tint/utils/string.h"
-
-namespace tint::ast {
-namespace {
-
-using InterpolateAttributeTest = TestHelper;
-
-TEST_F(InterpolateAttributeTest, Creation) {
-    auto* d =
-        create<InterpolateAttribute>(InterpolationType::kLinear, InterpolationSampling::kCenter);
-    EXPECT_EQ(InterpolationType::kLinear, d->type);
-    EXPECT_EQ(InterpolationSampling::kCenter, d->sampling);
-}
-
-namespace interpolation_type_tests {
-
-{{ Eval "TestParsePrintEnum" (Sem.Enum "interpolation_type")}}
-
-}  // namespace interpolation_type_tests
-
-namespace interpolation_sampling_tests {
-
-{{ Eval "TestParsePrintEnum" (Sem.Enum "interpolation_sampling")}}
-
-}  // namespace interpolation_sampling_tests
-
-}  // namespace
-}  // namespace tint::ast
diff --git a/src/tint/ast/invariant_attribute_test.cc b/src/tint/ast/invariant_attribute_test.cc
deleted file mode 100644
index edc7498..0000000
--- a/src/tint/ast/invariant_attribute_test.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2021 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/tint/ast/invariant_attribute.h"
-
-#include "src/tint/ast/test_helper.h"
-
-namespace tint::ast {
-namespace {
-
-using InvariantAttributeTest = TestHelper;
-
-}  // namespace
-}  // namespace tint::ast
diff --git a/src/tint/ast/location_attribute.cc b/src/tint/ast/location_attribute.cc
index 4f34144..b9b3f12 100644
--- a/src/tint/ast/location_attribute.cc
+++ b/src/tint/ast/location_attribute.cc
@@ -25,7 +25,7 @@
 LocationAttribute::LocationAttribute(ProgramID pid,
                                      NodeID nid,
                                      const Source& src,
-                                     const ast::Expression* exp)
+                                     const Expression* exp)
     : Base(pid, nid, src), expr(exp) {}
 
 LocationAttribute::~LocationAttribute() = default;
diff --git a/src/tint/ast/location_attribute.h b/src/tint/ast/location_attribute.h
index 43d5edf..a41e943 100644
--- a/src/tint/ast/location_attribute.h
+++ b/src/tint/ast/location_attribute.h
@@ -30,7 +30,7 @@
     /// @param nid the unique node identifier
     /// @param src the source of this node
     /// @param expr the location expression
-    LocationAttribute(ProgramID pid, NodeID nid, const Source& src, const ast::Expression* expr);
+    LocationAttribute(ProgramID pid, NodeID nid, const Source& src, const Expression* expr);
     ~LocationAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -43,7 +43,7 @@
     const LocationAttribute* Clone(CloneContext* ctx) const override;
 
     /// The location expression
-    const ast::Expression* const expr;
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/module.cc b/src/tint/ast/module.cc
index cbebab4..32dafe8 100644
--- a/src/tint/ast/module.cc
+++ b/src/tint/ast/module.cc
@@ -28,7 +28,7 @@
 Module::Module(ProgramID pid,
                NodeID nid,
                const Source& src,
-               utils::VectorRef<const ast::Node*> global_decls)
+               utils::VectorRef<const Node*> global_decls)
     : Base(pid, nid, src), global_declarations_(std::move(global_decls)) {
     for (auto* decl : global_declarations_) {
         if (decl == nullptr) {
@@ -41,7 +41,7 @@
 
 Module::~Module() = default;
 
-const ast::TypeDecl* Module::LookupType(Symbol name) const {
+const TypeDecl* Module::LookupType(Symbol name) const {
     for (auto* ty : TypeDecls()) {
         if (ty->name->symbol == name) {
             return ty;
@@ -59,7 +59,7 @@
 void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags) {
     Switch(
         decl,  //
-        [&](const ast::TypeDecl* type) {
+        [&](const TypeDecl* type) {
             TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
             type_decls_.Push(type);
         },
@@ -86,21 +86,21 @@
         [&](Default) { TINT_ICE(AST, diags) << "Unknown global declaration type"; });
 }
 
-void Module::AddDiagnosticDirective(const ast::DiagnosticDirective* directive) {
+void Module::AddDiagnosticDirective(const DiagnosticDirective* directive) {
     TINT_ASSERT(AST, directive);
     TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, directive, program_id);
     global_declarations_.Push(directive);
     diagnostic_directives_.Push(directive);
 }
 
-void Module::AddEnable(const ast::Enable* enable) {
+void Module::AddEnable(const Enable* enable) {
     TINT_ASSERT(AST, enable);
     TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id);
     global_declarations_.Push(enable);
     enables_.Push(enable);
 }
 
-void Module::AddGlobalVariable(const ast::Variable* var) {
+void Module::AddGlobalVariable(const Variable* var) {
     TINT_ASSERT(AST, var);
     TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
     global_variables_.Push(var);
@@ -114,14 +114,14 @@
     global_declarations_.Push(assertion);
 }
 
-void Module::AddTypeDecl(const ast::TypeDecl* type) {
+void Module::AddTypeDecl(const TypeDecl* type) {
     TINT_ASSERT(AST, type);
     TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
     type_decls_.Push(type);
     global_declarations_.Push(type);
 }
 
-void Module::AddFunction(const ast::Function* func) {
+void Module::AddFunction(const Function* func) {
     TINT_ASSERT(AST, func);
     TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
     functions_.Push(func);
diff --git a/src/tint/ast/module.h b/src/tint/ast/module.h
index a19f2bd..948f894 100644
--- a/src/tint/ast/module.h
+++ b/src/tint/ast/module.h
@@ -46,7 +46,7 @@
     Module(ProgramID pid,
            NodeID nid,
            const Source& src,
-           utils::VectorRef<const ast::Node*> global_decls);
+           utils::VectorRef<const Node*> global_decls);
 
     /// Destructor
     ~Module() override;
@@ -80,7 +80,7 @@
     auto& GlobalVariables() { return global_variables_; }
 
     /// @returns the global variable declarations of kind 'T' for the module
-    template <typename T, typename = traits::EnableIfIsType<T, ast::Variable>>
+    template <typename T, typename = traits::EnableIfIsType<T, Variable>>
     auto Globals() const {
         utils::Vector<const T*, 32> out;
         out.Reserve(global_variables_.Length());
diff --git a/src/tint/ast/module_clone_test.cc b/src/tint/ast/module_clone_test.cc
index 7bda881..eb7f775 100644
--- a/src/tint/ast/module_clone_test.cc
+++ b/src/tint/ast/module_clone_test.cc
@@ -42,8 +42,8 @@
 const c0 : i32 = 10;
 const c1 : bool = true;
 
-type t0 = array<vec4<f32>>;
-type t1 = array<vec4<f32>>;
+alias t0 = array<vec4<f32>>;
+alias t1 = array<vec4<f32>>;
 
 var<private> g0 : u32 = 20u;
 var<private> g1 : f32 = 123.0;
@@ -111,11 +111,11 @@
 
 const declaration_order_check_0 : i32 = 1;
 
-type declaration_order_check_1 = f32;
+alias declaration_order_check_1 = f32;
 
 fn declaration_order_check_2() {}
 
-type declaration_order_check_3 = f32;
+alias declaration_order_check_3 = f32;
 
 const declaration_order_check_4 : i32 = 1;
 
@@ -135,7 +135,7 @@
     EXPECT_EQ(Program::printer(&src), Program::printer(&dst));
 
     // Check that none of the AST nodes or type pointers in dst are found in src
-    std::unordered_set<const ast::Node*> src_nodes;
+    std::unordered_set<const Node*> src_nodes;
     for (auto* src_node : src.ASTNodes().Objects()) {
         src_nodes.emplace(src_node);
     }
diff --git a/src/tint/ast/module_test.cc b/src/tint/ast/module_test.cc
index 24faaee..c0255ff 100644
--- a/src/tint/ast/module_test.cc
+++ b/src/tint/ast/module_test.cc
@@ -61,9 +61,8 @@
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
-            b1.AST().AddFunction(b2.create<ast::Function>(b2.Ident("func"), utils::Empty,
-                                                          b2.ty.f32(), b2.Block(), utils::Empty,
-                                                          utils::Empty));
+            b1.AST().AddFunction(b2.create<Function>(b2.Ident("func"), utils::Empty, b2.ty.f32(),
+                                                     b2.Block(), utils::Empty, utils::Empty));
         },
         "internal compiler error");
 }
@@ -73,7 +72,7 @@
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
-            b1.AST().AddGlobalVariable(b2.Var("var", b2.ty.i32(), type::AddressSpace::kPrivate));
+            b1.AST().AddGlobalVariable(b2.Var("var", b2.ty.i32(), builtin::AddressSpace::kPrivate));
         },
         "internal compiler error");
 }
@@ -93,7 +92,7 @@
         ProgramBuilder b;
         b.Func("F", {}, b.ty.void_(), {});
         b.Alias("A", b.ty.u32());
-        b.GlobalVar("V", b.ty.i32(), type::AddressSpace::kPrivate);
+        b.GlobalVar("V", b.ty.i32(), builtin::AddressSpace::kPrivate);
         return Program(std::move(b));
     }();
 
@@ -102,7 +101,7 @@
     // declaration that triggered the ReplaceAll().
     ProgramBuilder cloned;
     CloneContext ctx(&cloned, &p);
-    ctx.ReplaceAll([&](const ast::Function*) -> const ast::Function* {
+    ctx.ReplaceAll([&](const Function*) -> const Function* {
         ctx.dst->Alias("inserted_before_F", cloned.ty.u32());
         return nullptr;
     });
@@ -110,7 +109,7 @@
         ctx.dst->Alias("inserted_before_A", cloned.ty.u32());
         return nullptr;
     });
-    ctx.ReplaceAll([&](const ast::Variable*) -> const ast::Variable* {
+    ctx.ReplaceAll([&](const Variable*) -> const Variable* {
         ctx.dst->Alias("inserted_before_V", cloned.ty.u32());
         return nullptr;
     });
@@ -118,9 +117,9 @@
 
     auto& decls = cloned.AST().GlobalDeclarations();
     ASSERT_EQ(decls.Length(), 6u);
-    EXPECT_TRUE(decls[1]->Is<ast::Function>());
+    EXPECT_TRUE(decls[1]->Is<Function>());
     EXPECT_TRUE(decls[3]->Is<ast::Alias>());
-    EXPECT_TRUE(decls[5]->Is<ast::Variable>());
+    EXPECT_TRUE(decls[5]->Is<Variable>());
 
     ASSERT_TRUE(decls[0]->Is<ast::Alias>());
     ASSERT_TRUE(decls[2]->Is<ast::Alias>());
@@ -136,9 +135,9 @@
 
 TEST_F(ModuleTest, Directives) {
     auto* enable_1 = Enable(builtin::Extension::kF16);
-    auto* diagnostic_1 = DiagnosticDirective(DiagnosticSeverity::kWarning, "foo");
+    auto* diagnostic_1 = DiagnosticDirective(builtin::DiagnosticSeverity::kWarning, "foo");
     auto* enable_2 = Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
-    auto* diagnostic_2 = DiagnosticDirective(DiagnosticSeverity::kOff, "bar");
+    auto* diagnostic_2 = DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "bar");
 
     this->SetResolveOnBuild(false);
     Program program(std::move(*this));
diff --git a/src/tint/ast/must_use_attribute.cc b/src/tint/ast/must_use_attribute.cc
new file mode 100644
index 0000000..dc1af16
--- /dev/null
+++ b/src/tint/ast/must_use_attribute.cc
@@ -0,0 +1,38 @@
+// Copyright 2023 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/tint/ast/must_use_attribute.h"
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::MustUseAttribute);
+
+namespace tint::ast {
+
+MustUseAttribute::MustUseAttribute(ProgramID pid, NodeID nid, const Source& src)
+    : Base(pid, nid, src) {}
+
+MustUseAttribute::~MustUseAttribute() = default;
+
+std::string MustUseAttribute::Name() const {
+    return "must_use";
+}
+
+const MustUseAttribute* MustUseAttribute::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<MustUseAttribute>(src);
+}
+
+}  // namespace tint::ast
diff --git a/src/tint/ast/must_use_attribute.h b/src/tint/ast/must_use_attribute.h
new file mode 100644
index 0000000..6befa54
--- /dev/null
+++ b/src/tint/ast/must_use_attribute.h
@@ -0,0 +1,46 @@
+// Copyright 2023 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_TINT_AST_MUST_USE_ATTRIBUTE_H_
+#define SRC_TINT_AST_MUST_USE_ATTRIBUTE_H_
+
+#include <string>
+
+#include "src/tint/ast/attribute.h"
+
+namespace tint::ast {
+
+/// The must_use attribute
+class MustUseAttribute final : public Castable<MustUseAttribute, Attribute> {
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param nid the unique node identifier
+    /// @param src the source of this node
+    MustUseAttribute(ProgramID pid, NodeID nid, const Source& src);
+    ~MustUseAttribute() override;
+
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
+
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const MustUseAttribute* Clone(CloneContext* ctx) const override;
+};
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_MUST_USE_ATTRIBUTE_H_
diff --git a/src/tint/ast/struct.cc b/src/tint/ast/struct.cc
index 2757c4e..96daeff 100644
--- a/src/tint/ast/struct.cc
+++ b/src/tint/ast/struct.cc
@@ -26,8 +26,8 @@
                NodeID nid,
                const Source& src,
                const Identifier* n,
-               utils::VectorRef<const ast::StructMember*> m,
-               utils::VectorRef<const ast::Attribute*> attrs)
+               utils::VectorRef<const StructMember*> m,
+               utils::VectorRef<const Attribute*> attrs)
     : Base(pid, nid, src, n), members(std::move(m)), attributes(std::move(attrs)) {
     for (auto* mem : members) {
         TINT_ASSERT(AST, mem);
diff --git a/src/tint/ast/struct.h b/src/tint/ast/struct.h
index 9668db1..36ad080 100644
--- a/src/tint/ast/struct.h
+++ b/src/tint/ast/struct.h
@@ -39,8 +39,8 @@
            NodeID nid,
            const Source& src,
            const Identifier* name,
-           utils::VectorRef<const ast::StructMember*> members,
-           utils::VectorRef<const ast::Attribute*> attributes);
+           utils::VectorRef<const StructMember*> members,
+           utils::VectorRef<const Attribute*> attributes);
     /// Move constructor
     Struct(Struct&&);
 
@@ -53,10 +53,10 @@
     const Struct* Clone(CloneContext* ctx) const override;
 
     /// The members
-    const utils::Vector<const ast::StructMember*, 8> members;
+    const utils::Vector<const StructMember*, 8> members;
 
     /// The struct attributes
-    const utils::Vector<const ast::Attribute*, 4> attributes;
+    const utils::Vector<const Attribute*, 4> attributes;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_align_attribute.cc b/src/tint/ast/struct_member_align_attribute.cc
index 2a21362..a7d69da 100644
--- a/src/tint/ast/struct_member_align_attribute.cc
+++ b/src/tint/ast/struct_member_align_attribute.cc
@@ -26,7 +26,7 @@
 StructMemberAlignAttribute::StructMemberAlignAttribute(ProgramID pid,
                                                        NodeID nid,
                                                        const Source& src,
-                                                       const ast::Expression* a)
+                                                       const Expression* a)
     : Base(pid, nid, src), expr(a) {}
 
 StructMemberAlignAttribute::~StructMemberAlignAttribute() = default;
diff --git a/src/tint/ast/struct_member_align_attribute.h b/src/tint/ast/struct_member_align_attribute.h
index 6da1894..1649ae6 100644
--- a/src/tint/ast/struct_member_align_attribute.h
+++ b/src/tint/ast/struct_member_align_attribute.h
@@ -34,7 +34,7 @@
     StructMemberAlignAttribute(ProgramID pid,
                                NodeID nid,
                                const Source& src,
-                               const ast::Expression* align);
+                               const Expression* align);
     ~StructMemberAlignAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -47,7 +47,7 @@
     const StructMemberAlignAttribute* Clone(CloneContext* ctx) const override;
 
     /// The align expression
-    const ast::Expression* const expr;
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_offset_attribute.cc b/src/tint/ast/struct_member_offset_attribute.cc
index 8b9faab..ee6f458 100644
--- a/src/tint/ast/struct_member_offset_attribute.cc
+++ b/src/tint/ast/struct_member_offset_attribute.cc
@@ -25,7 +25,7 @@
 StructMemberOffsetAttribute::StructMemberOffsetAttribute(ProgramID pid,
                                                          NodeID nid,
                                                          const Source& src,
-                                                         const ast::Expression* exp)
+                                                         const Expression* exp)
     : Base(pid, nid, src), expr(exp) {}
 
 StructMemberOffsetAttribute::~StructMemberOffsetAttribute() = default;
diff --git a/src/tint/ast/struct_member_offset_attribute.h b/src/tint/ast/struct_member_offset_attribute.h
index 632d71a..ed74397 100644
--- a/src/tint/ast/struct_member_offset_attribute.h
+++ b/src/tint/ast/struct_member_offset_attribute.h
@@ -42,7 +42,7 @@
     StructMemberOffsetAttribute(ProgramID pid,
                                 NodeID nid,
                                 const Source& src,
-                                const ast::Expression* expr);
+                                const Expression* expr);
     ~StructMemberOffsetAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -55,7 +55,7 @@
     const StructMemberOffsetAttribute* Clone(CloneContext* ctx) const override;
 
     /// The offset expression
-    const ast::Expression* const expr;
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_offset_attribute_test.cc b/src/tint/ast/struct_member_offset_attribute_test.cc
index 23dd697..6a7e4c9 100644
--- a/src/tint/ast/struct_member_offset_attribute_test.cc
+++ b/src/tint/ast/struct_member_offset_attribute_test.cc
@@ -22,8 +22,8 @@
 
 TEST_F(StructMemberOffsetAttributeTest, Creation) {
     auto* d = MemberOffset(2_u);
-    ASSERT_TRUE(d->expr->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(2u, d->expr->As<ast::IntLiteralExpression>()->value);
+    ASSERT_TRUE(d->expr->Is<IntLiteralExpression>());
+    EXPECT_EQ(2u, d->expr->As<IntLiteralExpression>()->value);
 }
 
 }  // namespace
diff --git a/src/tint/ast/struct_member_size_attribute.cc b/src/tint/ast/struct_member_size_attribute.cc
index 833896d..8d08ca8 100644
--- a/src/tint/ast/struct_member_size_attribute.cc
+++ b/src/tint/ast/struct_member_size_attribute.cc
@@ -26,7 +26,7 @@
 StructMemberSizeAttribute::StructMemberSizeAttribute(ProgramID pid,
                                                      NodeID nid,
                                                      const Source& src,
-                                                     const ast::Expression* exp)
+                                                     const Expression* exp)
     : Base(pid, nid, src), expr(exp) {}
 
 StructMemberSizeAttribute::~StructMemberSizeAttribute() = default;
diff --git a/src/tint/ast/struct_member_size_attribute.h b/src/tint/ast/struct_member_size_attribute.h
index c048b1f..2a0c71f 100644
--- a/src/tint/ast/struct_member_size_attribute.h
+++ b/src/tint/ast/struct_member_size_attribute.h
@@ -31,10 +31,7 @@
     /// @param nid the unique node identifier
     /// @param src the source of this node
     /// @param expr the size expression
-    StructMemberSizeAttribute(ProgramID pid,
-                              NodeID nid,
-                              const Source& src,
-                              const ast::Expression* expr);
+    StructMemberSizeAttribute(ProgramID pid, NodeID nid, const Source& src, const Expression* expr);
     ~StructMemberSizeAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -47,7 +44,7 @@
     const StructMemberSizeAttribute* Clone(CloneContext* ctx) const override;
 
     /// The size expression
-    const ast::Expression* const expr;
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_size_attribute_test.cc b/src/tint/ast/struct_member_size_attribute_test.cc
index 9f6b49b..17e4ae6 100644
--- a/src/tint/ast/struct_member_size_attribute_test.cc
+++ b/src/tint/ast/struct_member_size_attribute_test.cc
@@ -24,8 +24,8 @@
 
 TEST_F(StructMemberSizeAttributeTest, Creation) {
     auto* d = MemberSize(2_u);
-    ASSERT_TRUE(d->expr->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(2u, d->expr->As<ast::IntLiteralExpression>()->value);
+    ASSERT_TRUE(d->expr->Is<IntLiteralExpression>());
+    EXPECT_EQ(2u, d->expr->As<IntLiteralExpression>()->value);
 }
 
 }  // namespace
diff --git a/src/tint/ast/struct_member_test.cc b/src/tint/ast/struct_member_test.cc
index 94a072f..59eb30f 100644
--- a/src/tint/ast/struct_member_test.cc
+++ b/src/tint/ast/struct_member_test.cc
@@ -23,8 +23,8 @@
 
 TEST_F(StructMemberTest, Creation) {
     auto* st = Member("a", ty.i32(), utils::Vector{MemberSize(4_a)});
-    ast::CheckIdentifier(Symbols(), st->name, "a");
-    ast::CheckIdentifier(Symbols(), st->type, "i32");
+    CheckIdentifier(Symbols(), st->name, "a");
+    CheckIdentifier(Symbols(), st->type, "i32");
     EXPECT_EQ(st->attributes.Length(), 1u);
     EXPECT_TRUE(st->attributes[0]->Is<StructMemberSizeAttribute>());
     EXPECT_EQ(st->source.range.begin.line, 0u);
@@ -36,8 +36,8 @@
 TEST_F(StructMemberTest, CreationWithSource) {
     auto* st = Member(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}}, "a",
                       ty.i32());
-    ast::CheckIdentifier(Symbols(), st->name, "a");
-    ast::CheckIdentifier(Symbols(), st->type, "i32");
+    CheckIdentifier(Symbols(), st->name, "a");
+    CheckIdentifier(Symbols(), st->type, "i32");
     EXPECT_EQ(st->attributes.Length(), 0u);
     EXPECT_EQ(st->source.range.begin.line, 27u);
     EXPECT_EQ(st->source.range.begin.column, 4u);
@@ -58,7 +58,7 @@
     EXPECT_FATAL_FAILURE(
         {
             ProgramBuilder b;
-            b.Member("a", ast::Type{});
+            b.Member("a", Type{});
         },
         "internal compiler error");
 }
diff --git a/src/tint/ast/struct_test.cc b/src/tint/ast/struct_test.cc
index cfb4181..1d14716 100644
--- a/src/tint/ast/struct_test.cc
+++ b/src/tint/ast/struct_test.cc
@@ -83,7 +83,7 @@
         {
             ProgramBuilder b;
             b.Structure(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32())},
-                        utils::Vector<const ast::Attribute*, 1>{nullptr});
+                        utils::Vector<const Attribute*, 1>{nullptr});
         },
         "internal compiler error");
 }
diff --git a/src/tint/ast/switch_statement_test.cc b/src/tint/ast/switch_statement_test.cc
index 00c515e..e6101c8 100644
--- a/src/tint/ast/switch_statement_test.cc
+++ b/src/tint/ast/switch_statement_test.cc
@@ -53,7 +53,7 @@
 }
 
 TEST_F(SwitchStatementTest, Assert_Null_Condition) {
-    using CaseStatementList = utils::Vector<const ast::CaseStatement*, 2>;
+    using CaseStatementList = utils::Vector<const CaseStatement*, 2>;
     EXPECT_FATAL_FAILURE(
         {
             ProgramBuilder b;
@@ -66,7 +66,7 @@
 }
 
 TEST_F(SwitchStatementTest, Assert_Null_CaseStatement) {
-    using CaseStatementList = utils::Vector<const ast::CaseStatement*, 2>;
+    using CaseStatementList = utils::Vector<const CaseStatement*, 2>;
     EXPECT_FATAL_FAILURE(
         {
             ProgramBuilder b;
diff --git a/src/tint/ast/templated_identifier_test.cc b/src/tint/ast/templated_identifier_test.cc
index 648c334..ce62c79 100644
--- a/src/tint/ast/templated_identifier_test.cc
+++ b/src/tint/ast/templated_identifier_test.cc
@@ -26,21 +26,25 @@
 TEST_F(TemplatedIdentifierTest, Creation) {
     auto* i = Ident("ident", 1_a, Add("x", "y"), false, "x");
     EXPECT_EQ(i->symbol, Symbols().Get("ident"));
-    ASSERT_EQ(i->arguments.Length(), 4u);
-    EXPECT_TRUE(i->arguments[0]->Is<ast::IntLiteralExpression>());
-    EXPECT_TRUE(i->arguments[1]->Is<ast::BinaryExpression>());
-    EXPECT_TRUE(i->arguments[2]->Is<ast::BoolLiteralExpression>());
-    EXPECT_TRUE(i->arguments[3]->Is<ast::IdentifierExpression>());
+    auto* t = i->As<TemplatedIdentifier>();
+    ASSERT_NE(t, nullptr);
+    ASSERT_EQ(t->arguments.Length(), 4u);
+    EXPECT_TRUE(t->arguments[0]->Is<IntLiteralExpression>());
+    EXPECT_TRUE(t->arguments[1]->Is<BinaryExpression>());
+    EXPECT_TRUE(t->arguments[2]->Is<BoolLiteralExpression>());
+    EXPECT_TRUE(t->arguments[3]->Is<IdentifierExpression>());
 }
 
 TEST_F(TemplatedIdentifierTest, Creation_WithSource) {
     auto* i = Ident(Source{{20, 2}}, "ident", 1_a, Add("x", "y"), false, "x");
     EXPECT_EQ(i->symbol, Symbols().Get("ident"));
-    ASSERT_EQ(i->arguments.Length(), 4u);
-    EXPECT_TRUE(i->arguments[0]->Is<ast::IntLiteralExpression>());
-    EXPECT_TRUE(i->arguments[1]->Is<ast::BinaryExpression>());
-    EXPECT_TRUE(i->arguments[2]->Is<ast::BoolLiteralExpression>());
-    EXPECT_TRUE(i->arguments[3]->Is<ast::IdentifierExpression>());
+    auto* t = i->As<TemplatedIdentifier>();
+    ASSERT_NE(t, nullptr);
+    ASSERT_EQ(t->arguments.Length(), 4u);
+    EXPECT_TRUE(t->arguments[0]->Is<IntLiteralExpression>());
+    EXPECT_TRUE(t->arguments[1]->Is<BinaryExpression>());
+    EXPECT_TRUE(t->arguments[2]->Is<BoolLiteralExpression>());
+    EXPECT_TRUE(t->arguments[3]->Is<IdentifierExpression>());
 
     auto src = i->source;
     EXPECT_EQ(src.range.begin.line, 20u);
diff --git a/src/tint/ast/traverse_expressions.h b/src/tint/ast/traverse_expressions.h
index 629e010..fb8aad1 100644
--- a/src/tint/ast/traverse_expressions.h
+++ b/src/tint/ast/traverse_expressions.h
@@ -57,24 +57,22 @@
 /// @param diags the diagnostics used for error messages
 /// @param callback the callback function. Must be of the signature:
 ///        `TraverseAction(const T* expr)` or `TraverseAction(const T* expr, size_t depth)` where T
-///        is an ast::Expression type.
+///        is an Expression type.
 /// @return true on success, false on error
 template <TraverseOrder ORDER = TraverseOrder::LeftToRight, typename CALLBACK>
-bool TraverseExpressions(const ast::Expression* root, diag::List& diags, CALLBACK&& callback) {
+bool TraverseExpressions(const Expression* root, diag::List& diags, CALLBACK&& callback) {
     using EXPR_TYPE = std::remove_pointer_t<traits::ParameterType<CALLBACK, 0>>;
     constexpr static bool kHasDepthArg = traits::SignatureOfT<CALLBACK>::parameter_count == 2;
 
     struct Pending {
-        const ast::Expression* expr;
+        const Expression* expr;
         size_t depth;
     };
 
     utils::Vector<Pending, 32> to_visit{{root, 0}};
 
-    auto push_single = [&](const ast::Expression* expr, size_t depth) {
-        to_visit.Push({expr, depth});
-    };
-    auto push_pair = [&](const ast::Expression* left, const ast::Expression* right, size_t depth) {
+    auto push_single = [&](const Expression* expr, size_t depth) { to_visit.Push({expr, depth}); };
+    auto push_pair = [&](const Expression* left, const Expression* right, size_t depth) {
         if (ORDER == TraverseOrder::LeftToRight) {
             to_visit.Push({right, depth});
             to_visit.Push({left, depth});
@@ -83,7 +81,7 @@
             to_visit.Push({right, depth});
         }
     };
-    auto push_list = [&](utils::VectorRef<const ast::Expression*> exprs, size_t depth) {
+    auto push_list = [&](utils::VectorRef<const Expression*> exprs, size_t depth) {
         if (ORDER == TraverseOrder::LeftToRight) {
             for (auto* expr : utils::Reverse(exprs)) {
                 to_visit.Push({expr, depth});
@@ -97,7 +95,7 @@
 
     while (!to_visit.IsEmpty()) {
         auto p = to_visit.Pop();
-        const ast::Expression* expr = p.expr;
+        const Expression* expr = p.expr;
 
         if (auto* filtered = expr->template As<EXPR_TYPE>()) {
             TraverseAction result;
diff --git a/src/tint/ast/traverse_expressions_test.cc b/src/tint/ast/traverse_expressions_test.cc
index f0226aa..0db73c2 100644
--- a/src/tint/ast/traverse_expressions_test.cc
+++ b/src/tint/ast/traverse_expressions_test.cc
@@ -26,66 +26,66 @@
 using TraverseExpressionsTest = TestHelper;
 
 TEST_F(TraverseExpressionsTest, DescendIndexAccessor) {
-    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
-    std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
+    std::vector<const Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
     auto* root = IndexAccessor(i[0], i[1]);
     {
-        std::vector<const ast::Expression*> l2r;
+        std::vector<const Expression*> l2r;
         TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             l2r.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
     }
     {
-        std::vector<const ast::Expression*> r2l;
+        std::vector<const Expression*> r2l;
         TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             r2l.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
     }
 }
 
 TEST_F(TraverseExpressionsTest, DescendBinaryExpression) {
-    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
-    std::vector<const ast::Expression*> i = {Add(e[0], e[1]), Sub(e[2], e[3])};
+    std::vector<const Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const Expression*> i = {Add(e[0], e[1]), Sub(e[2], e[3])};
     auto* root = Mul(i[0], i[1]);
     {
-        std::vector<const ast::Expression*> l2r;
+        std::vector<const Expression*> l2r;
         TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             l2r.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
     }
     {
-        std::vector<const ast::Expression*> r2l;
+        std::vector<const Expression*> r2l;
         TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             r2l.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
     }
 }
 
 TEST_F(TraverseExpressionsTest, Depth) {
-    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
-    std::vector<const ast::Expression*> i = {Add(e[0], e[1]), Sub(e[2], e[3])};
+    std::vector<const Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const Expression*> i = {Add(e[0], e[1]), Sub(e[2], e[3])};
     auto* root = Mul(i[0], i[1]);
 
     size_t j = 0;
     size_t depths[] = {0, 1, 2, 2, 1, 2, 2};
     {
         TraverseExpressions<TraverseOrder::LeftToRight>(  //
-            root, Diagnostics(), [&](const ast::Expression* expr, size_t depth) {
+            root, Diagnostics(), [&](const Expression* expr, size_t depth) {
                 (void)expr;
                 EXPECT_THAT(depth, depths[j++]);
-                return ast::TraverseAction::Descend;
+                return TraverseAction::Descend;
             });
     }
 }
@@ -97,20 +97,20 @@
     auto* b2 = Bitcast<i32>(b1);
     auto* root = Bitcast<i32>(b2);
     {
-        utils::Vector<const ast::Expression*, 8> l2r;
+        utils::Vector<const Expression*, 8> l2r;
         TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             l2r.Push(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(l2r, ElementsAre(root, b2, b1, b0, e));
     }
     {
-        utils::Vector<const ast::Expression*, 8> r2l;
+        utils::Vector<const Expression*, 8> r2l;
         TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             r2l.Push(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(r2l, ElementsAre(root, b2, b1, b0, e));
     }
@@ -121,20 +121,20 @@
     utils::Vector c{Call("a", e[0], e[1]), Call("b", e[2], e[3])};
     auto* root = Call("c", c[0], c[1]);
     {
-        utils::Vector<const ast::Expression*, 8> l2r;
+        utils::Vector<const Expression*, 8> l2r;
         TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             l2r.Push(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(l2r, ElementsAre(root, c[0], e[0], e[1], c[1], e[2], e[3]));
     }
     {
-        utils::Vector<const ast::Expression*, 8> r2l;
+        utils::Vector<const Expression*, 8> r2l;
         TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             r2l.Push(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(r2l, ElementsAre(root, c[1], e[3], e[2], c[0], e[1], e[0]));
     }
@@ -145,20 +145,20 @@
     auto* m = MemberAccessor(e, "a");
     auto* root = MemberAccessor(m, "b");
     {
-        std::vector<const ast::Expression*> l2r;
+        std::vector<const Expression*> l2r;
         TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             l2r.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(l2r, ElementsAre(root, m, e));
     }
     {
-        std::vector<const ast::Expression*> r2l;
+        std::vector<const Expression*> r2l;
         TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             r2l.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(r2l, ElementsAre(root, m, e));
     }
@@ -173,20 +173,20 @@
     auto* f = IndexAccessor(d, e);
     auto* root = IndexAccessor(c, f);
     {
-        std::vector<const ast::Expression*> l2r;
+        std::vector<const Expression*> l2r;
         TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             l2r.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(l2r, ElementsAre(root, c, a, b, f, d, e));
     }
     {
-        std::vector<const ast::Expression*> r2l;
+        std::vector<const Expression*> r2l;
         TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             r2l.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(r2l, ElementsAre(root, f, e, d, c, b, a));
     }
@@ -199,47 +199,47 @@
     auto* u2 = AddressOf(u1);
     auto* root = Deref(u2);
     {
-        std::vector<const ast::Expression*> l2r;
+        std::vector<const Expression*> l2r;
         TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             l2r.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(l2r, ElementsAre(root, u2, u1, u0, e));
     }
     {
-        std::vector<const ast::Expression*> r2l;
+        std::vector<const Expression*> r2l;
         TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const ast::Expression* expr) {
+                                                        [&](const Expression* expr) {
                                                             r2l.push_back(expr);
-                                                            return ast::TraverseAction::Descend;
+                                                            return TraverseAction::Descend;
                                                         });
         EXPECT_THAT(r2l, ElementsAre(root, u2, u1, u0, e));
     }
 }
 
 TEST_F(TraverseExpressionsTest, Skip) {
-    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
-    std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
+    std::vector<const Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
     auto* root = IndexAccessor(i[0], i[1]);
-    std::vector<const ast::Expression*> order;
+    std::vector<const Expression*> order;
     TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
+        root, Diagnostics(), [&](const Expression* expr) {
             order.push_back(expr);
-            return expr == i[0] ? ast::TraverseAction::Skip : ast::TraverseAction::Descend;
+            return expr == i[0] ? TraverseAction::Skip : TraverseAction::Descend;
         });
     EXPECT_THAT(order, ElementsAre(root, i[0], i[1], e[2], e[3]));
 }
 
 TEST_F(TraverseExpressionsTest, Stop) {
-    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
-    std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
+    std::vector<const Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
     auto* root = IndexAccessor(i[0], i[1]);
-    std::vector<const ast::Expression*> order;
+    std::vector<const Expression*> order;
     TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
+        root, Diagnostics(), [&](const Expression* expr) {
             order.push_back(expr);
-            return expr == i[0] ? ast::TraverseAction::Stop : ast::TraverseAction::Descend;
+            return expr == i[0] ? TraverseAction::Stop : TraverseAction::Descend;
         });
     EXPECT_THAT(order, ElementsAre(root, i[0]));
 }
diff --git a/src/tint/ast/var.cc b/src/tint/ast/var.cc
index b748381..bccdbcc 100644
--- a/src/tint/ast/var.cc
+++ b/src/tint/ast/var.cc
@@ -25,8 +25,8 @@
          const Source& src,
          const Identifier* n,
          Type ty,
-         type::AddressSpace address_space,
-         type::Access access,
+         const Expression* address_space,
+         const Expression* access,
          const Expression* init,
          utils::VectorRef<const Attribute*> attrs)
     : Base(pid, nid, src, n, ty, init, std::move(attrs)),
@@ -45,10 +45,11 @@
     auto src = ctx->Clone(source);
     auto* n = ctx->Clone(name);
     auto ty = ctx->Clone(type);
+    auto* address_space = ctx->Clone(declared_address_space);
+    auto* access = ctx->Clone(declared_access);
     auto* init = ctx->Clone(initializer);
     auto attrs = ctx->Clone(attributes);
-    return ctx->dst->create<Var>(src, n, ty, declared_address_space, declared_access, init,
-                                 std::move(attrs));
+    return ctx->dst->create<Var>(src, n, ty, address_space, access, init, std::move(attrs));
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/var.h b/src/tint/ast/var.h
index e3537d1..006d8de 100644
--- a/src/tint/ast/var.h
+++ b/src/tint/ast/var.h
@@ -56,8 +56,8 @@
         const Source& source,
         const Identifier* name,
         Type type,
-        type::AddressSpace declared_address_space,
-        type::Access declared_access,
+        const Expression* declared_address_space,
+        const Expression* declared_access,
         const Expression* initializer,
         utils::VectorRef<const Attribute*> attributes);
 
@@ -77,10 +77,10 @@
     const Var* Clone(CloneContext* ctx) const override;
 
     /// The declared address space
-    const type::AddressSpace declared_address_space;
+    const Expression* const declared_address_space = nullptr;
 
     /// The declared access control
-    const type::Access declared_access;
+    const Expression* const declared_access = nullptr;
 };
 
 /// A list of `var` declarations
diff --git a/src/tint/ast/variable.h b/src/tint/ast/variable.h
index 7663e4f..70e5116 100644
--- a/src/tint/ast/variable.h
+++ b/src/tint/ast/variable.h
@@ -23,8 +23,8 @@
 #include "src/tint/ast/expression.h"
 #include "src/tint/ast/group_attribute.h"
 #include "src/tint/ast/type.h"
-#include "src/tint/type/access.h"
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/address_space.h"
 
 // Forward declarations
 namespace tint::ast {
@@ -66,8 +66,8 @@
 
     /// @returns true if the variable has both group and binding attributes
     bool HasBindingPoint() const {
-        return ast::GetAttribute<ast::BindingAttribute>(attributes) != nullptr &&
-               ast::GetAttribute<ast::GroupAttribute>(attributes) != nullptr;
+        return HasAttribute<BindingAttribute>(attributes) &&
+               HasAttribute<GroupAttribute>(attributes);
     }
 
     /// @returns the kind of the variable, which can be used in diagnostics
diff --git a/src/tint/ast/variable_test.cc b/src/tint/ast/variable_test.cc
index 88bcdc4..6fbc420 100644
--- a/src/tint/ast/variable_test.cc
+++ b/src/tint/ast/variable_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/ast/test_helper.h"
+#include "src/tint/builtin/builtin_value.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -25,10 +26,11 @@
 using VariableTest = TestHelper;
 
 TEST_F(VariableTest, Creation) {
-    auto* v = Var("my_var", ty.i32(), type::AddressSpace::kFunction);
+    auto* v = Var("my_var", ty.i32(), builtin::AddressSpace::kFunction);
 
     CheckIdentifier(Symbols(), v->name, "my_var");
-    EXPECT_EQ(v->declared_address_space, type::AddressSpace::kFunction);
+    CheckIdentifier(Symbols(), v->declared_address_space, "function");
+    EXPECT_EQ(v->declared_access, nullptr);
     CheckIdentifier(Symbols(), v->type, "i32");
     EXPECT_EQ(v->source.range.begin.line, 0u);
     EXPECT_EQ(v->source.range.begin.column, 0u);
@@ -38,10 +40,10 @@
 
 TEST_F(VariableTest, CreationWithSource) {
     auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}}, "i",
-                  ty.f32(), type::AddressSpace::kPrivate, utils::Empty);
+                  ty.f32(), builtin::AddressSpace::kPrivate, utils::Empty);
 
     CheckIdentifier(Symbols(), v->name, "i");
-    EXPECT_EQ(v->declared_address_space, type::AddressSpace::kPrivate);
+    CheckIdentifier(Symbols(), v->declared_address_space, "private");
     CheckIdentifier(Symbols(), v->type, "f32");
     EXPECT_EQ(v->source.range.begin.line, 27u);
     EXPECT_EQ(v->source.range.begin.column, 4u);
@@ -51,10 +53,10 @@
 
 TEST_F(VariableTest, CreationEmpty) {
     auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}}, "a_var",
-                  ty.i32(), type::AddressSpace::kWorkgroup, utils::Empty);
+                  ty.i32(), builtin::AddressSpace::kWorkgroup, utils::Empty);
 
     CheckIdentifier(Symbols(), v->name, "a_var");
-    EXPECT_EQ(v->declared_address_space, type::AddressSpace::kWorkgroup);
+    CheckIdentifier(Symbols(), v->declared_address_space, "workgroup");
     CheckIdentifier(Symbols(), v->type, "i32");
     EXPECT_EQ(v->source.range.begin.line, 27u);
     EXPECT_EQ(v->source.range.begin.column, 4u);
@@ -92,37 +94,37 @@
 }
 
 TEST_F(VariableTest, WithAttributes) {
-    auto* var = Var("my_var", ty.i32(), type::AddressSpace::kFunction, Location(1_u),
+    auto* var = Var("my_var", ty.i32(), builtin::AddressSpace::kFunction, Location(1_u),
                     Builtin(builtin::BuiltinValue::kPosition), Id(1200_u));
 
     auto& attributes = var->attributes;
-    EXPECT_TRUE(ast::HasAttribute<ast::LocationAttribute>(attributes));
-    EXPECT_TRUE(ast::HasAttribute<ast::BuiltinAttribute>(attributes));
-    EXPECT_TRUE(ast::HasAttribute<ast::IdAttribute>(attributes));
+    EXPECT_TRUE(ast::HasAttribute<LocationAttribute>(attributes));
+    EXPECT_TRUE(ast::HasAttribute<BuiltinAttribute>(attributes));
+    EXPECT_TRUE(ast::HasAttribute<IdAttribute>(attributes));
 
-    auto* location = ast::GetAttribute<ast::LocationAttribute>(attributes);
+    auto* location = GetAttribute<LocationAttribute>(attributes);
     ASSERT_NE(nullptr, location);
     ASSERT_NE(nullptr, location->expr);
-    EXPECT_TRUE(location->expr->Is<ast::IntLiteralExpression>());
+    EXPECT_TRUE(location->expr->Is<IntLiteralExpression>());
 }
 
 TEST_F(VariableTest, HasBindingPoint_BothProvided) {
-    auto* var = Var("my_var", ty.i32(), type::AddressSpace::kFunction, Binding(2_a), Group(1_a));
+    auto* var = Var("my_var", ty.i32(), builtin::AddressSpace::kFunction, Binding(2_a), Group(1_a));
     EXPECT_TRUE(var->HasBindingPoint());
 }
 
 TEST_F(VariableTest, HasBindingPoint_NeitherProvided) {
-    auto* var = Var("my_var", ty.i32(), type::AddressSpace::kFunction, utils::Empty);
+    auto* var = Var("my_var", ty.i32(), builtin::AddressSpace::kFunction, utils::Empty);
     EXPECT_FALSE(var->HasBindingPoint());
 }
 
 TEST_F(VariableTest, HasBindingPoint_MissingGroupAttribute) {
-    auto* var = Var("my_var", ty.i32(), type::AddressSpace::kFunction, Binding(2_a));
+    auto* var = Var("my_var", ty.i32(), builtin::AddressSpace::kFunction, Binding(2_a));
     EXPECT_FALSE(var->HasBindingPoint());
 }
 
 TEST_F(VariableTest, HasBindingPoint_MissingBindingAttribute) {
-    auto* var = Var("my_var", ty.i32(), type::AddressSpace::kFunction, Group(1_a));
+    auto* var = Var("my_var", ty.i32(), builtin::AddressSpace::kFunction, Group(1_a));
     EXPECT_FALSE(var->HasBindingPoint());
 }
 
diff --git a/src/tint/ast/workgroup_attribute.cc b/src/tint/ast/workgroup_attribute.cc
index 7cb67dc..3167f59 100644
--- a/src/tint/ast/workgroup_attribute.cc
+++ b/src/tint/ast/workgroup_attribute.cc
@@ -25,9 +25,9 @@
 WorkgroupAttribute::WorkgroupAttribute(ProgramID pid,
                                        NodeID nid,
                                        const Source& src,
-                                       const ast::Expression* x_,
-                                       const ast::Expression* y_,
-                                       const ast::Expression* z_)
+                                       const Expression* x_,
+                                       const Expression* y_,
+                                       const Expression* z_)
     : Base(pid, nid, src), x(x_), y(y_), z(z_) {}
 
 WorkgroupAttribute::~WorkgroupAttribute() = default;
diff --git a/src/tint/ast/workgroup_attribute.h b/src/tint/ast/workgroup_attribute.h
index e27e77e..05cbb89 100644
--- a/src/tint/ast/workgroup_attribute.h
+++ b/src/tint/ast/workgroup_attribute.h
@@ -40,14 +40,14 @@
     WorkgroupAttribute(ProgramID pid,
                        NodeID nid,
                        const Source& src,
-                       const ast::Expression* x,
-                       const ast::Expression* y = nullptr,
-                       const ast::Expression* z = nullptr);
+                       const Expression* x,
+                       const Expression* y = nullptr,
+                       const Expression* z = nullptr);
 
     ~WorkgroupAttribute() override;
 
     /// @returns the workgroup dimensions
-    std::array<const ast::Expression*, 3> Values() const { return {x, y, z}; }
+    std::array<const Expression*, 3> Values() const { return {x, y, z}; }
 
     /// @returns the WGSL name for the attribute
     std::string Name() const override;
@@ -59,11 +59,11 @@
     const WorkgroupAttribute* Clone(CloneContext* ctx) const override;
 
     /// The workgroup x dimension.
-    const ast::Expression* const x;
+    const Expression* const x;
     /// The optional workgroup y dimension. May be null.
-    const ast::Expression* const y = nullptr;
+    const Expression* const y = nullptr;
     /// The optional workgroup z dimension. May be null.
-    const ast::Expression* const z = nullptr;
+    const Expression* const z = nullptr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/workgroup_attribute_test.cc b/src/tint/ast/workgroup_attribute_test.cc
index 97a034b..3363e52 100644
--- a/src/tint/ast/workgroup_attribute_test.cc
+++ b/src/tint/ast/workgroup_attribute_test.cc
@@ -28,8 +28,8 @@
     auto* d = WorkgroupSize(2_i);
     auto values = d->Values();
 
-    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
+    ASSERT_TRUE(values[0]->Is<IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<IntLiteralExpression>()->value, 2);
 
     EXPECT_EQ(values[1], nullptr);
     EXPECT_EQ(values[2], nullptr);
@@ -38,11 +38,11 @@
     auto* d = WorkgroupSize(2_i, 4_i);
     auto values = d->Values();
 
-    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
+    ASSERT_TRUE(values[0]->Is<IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<IntLiteralExpression>()->value, 2);
 
-    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 4);
+    ASSERT_TRUE(values[1]->Is<IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<IntLiteralExpression>()->value, 4);
 
     EXPECT_EQ(values[2], nullptr);
 }
@@ -51,27 +51,27 @@
     auto* d = WorkgroupSize(2_i, 4_i, 6_i);
     auto values = d->Values();
 
-    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
+    ASSERT_TRUE(values[0]->Is<IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<IntLiteralExpression>()->value, 2);
 
-    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 4);
+    ASSERT_TRUE(values[1]->Is<IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<IntLiteralExpression>()->value, 4);
 
-    ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->value, 6);
+    ASSERT_TRUE(values[2]->Is<IntLiteralExpression>());
+    EXPECT_EQ(values[2]->As<IntLiteralExpression>()->value, 6);
 }
 
 TEST_F(WorkgroupAttributeTest, Creation_WithIdentifier) {
     auto* d = WorkgroupSize(2_i, 4_i, "depth");
     auto values = d->Values();
 
-    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
+    ASSERT_TRUE(values[0]->Is<IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<IntLiteralExpression>()->value, 2);
 
-    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 4);
+    ASSERT_TRUE(values[1]->Is<IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<IntLiteralExpression>()->value, 4);
 
-    auto* z_ident = As<ast::IdentifierExpression>(values[2]);
+    auto* z_ident = As<IdentifierExpression>(values[2]);
     ASSERT_TRUE(z_ident);
     EXPECT_EQ(Symbols().NameFor(z_ident->identifier->symbol), "depth");
 }
diff --git a/src/tint/type/access.cc b/src/tint/builtin/access.cc
similarity index 92%
rename from src/tint/type/access.cc
rename to src/tint/builtin/access.cc
index 04ccd9d..56b326c 100644
--- a/src/tint/type/access.cc
+++ b/src/tint/builtin/access.cc
@@ -15,14 +15,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/access.cc.tmpl
+//   src/tint/builtin/access.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/access.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// ParseAccess parses a Access from a string.
 /// @param str the string to parse
@@ -54,4 +54,4 @@
     return out << "<unknown>";
 }
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/access.cc.tmpl b/src/tint/builtin/access.cc.tmpl
similarity index 86%
rename from src/tint/type/access.cc.tmpl
rename to src/tint/builtin/access.cc.tmpl
index b34ff61..d0f967f 100644
--- a/src/tint/type/access.cc.tmpl
+++ b/src/tint/builtin/access.cc.tmpl
@@ -14,12 +14,12 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "access") -}}
 
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/access.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 {{ Eval "ParseEnum" $enum}}
 
 {{ Eval "EnumOStream" $enum}}
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/access.h b/src/tint/builtin/access.h
similarity index 87%
rename from src/tint/type/access.h
rename to src/tint/builtin/access.h
index 26f24f6..f59f50e 100644
--- a/src/tint/type/access.h
+++ b/src/tint/builtin/access.h
@@ -15,17 +15,17 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/access.h.tmpl
+//   src/tint/builtin/access.h.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#ifndef SRC_TINT_TYPE_ACCESS_H_
-#define SRC_TINT_TYPE_ACCESS_H_
+#ifndef SRC_TINT_BUILTIN_ACCESS_H_
+#define SRC_TINT_BUILTIN_ACCESS_H_
 
 #include <ostream>
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// Address space of a given pointer.
 enum class Access {
@@ -51,6 +51,6 @@
     "write",
 };
 
-}  // namespace tint::type
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_TYPE_ACCESS_H_
+#endif  // SRC_TINT_BUILTIN_ACCESS_H_
diff --git a/src/tint/type/access.h.tmpl b/src/tint/builtin/access.h.tmpl
similarity index 79%
rename from src/tint/type/access.h.tmpl
rename to src/tint/builtin/access.h.tmpl
index 6d353e5..6e4587a 100644
--- a/src/tint/type/access.h.tmpl
+++ b/src/tint/builtin/access.h.tmpl
@@ -14,16 +14,16 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "access") -}}
 
-#ifndef SRC_TINT_TYPE_ACCESS_H_
-#define SRC_TINT_TYPE_ACCESS_H_
+#ifndef SRC_TINT_BUILTIN_ACCESS_H_
+#define SRC_TINT_BUILTIN_ACCESS_H_
 
 #include <ostream>
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// Address space of a given pointer.
 {{ Eval "DeclareEnum" $enum}}
 
-}  // namespace tint::type
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_TYPE_ACCESS_H_
+#endif  // SRC_TINT_BUILTIN_ACCESS_H_
diff --git a/src/tint/type/access_bench.cc b/src/tint/builtin/access_bench.cc
similarity index 91%
rename from src/tint/type/access_bench.cc
rename to src/tint/builtin/access_bench.cc
index ab578eb..91f808f 100644
--- a/src/tint/type/access_bench.cc
+++ b/src/tint/builtin/access_bench.cc
@@ -15,18 +15,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/access_bench.cc.tmpl
+//   src/tint/builtin/access_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/access.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 void AccessParser(::benchmark::State& state) {
@@ -48,4 +48,4 @@
 BENCHMARK(AccessParser);
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/access_bench.cc.tmpl b/src/tint/builtin/access_bench.cc.tmpl
similarity index 87%
rename from src/tint/type/access_bench.cc.tmpl
rename to src/tint/builtin/access_bench.cc.tmpl
index 420f486..c701ab9 100644
--- a/src/tint/type/access_bench.cc.tmpl
+++ b/src/tint/builtin/access_bench.cc.tmpl
@@ -14,16 +14,16 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "access") -}}
 
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/access.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" $enum }}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/access_test.cc b/src/tint/builtin/access_test.cc
similarity index 93%
rename from src/tint/type/access_test.cc
rename to src/tint/builtin/access_test.cc
index 77968ef..91786ef 100644
--- a/src/tint/type/access_test.cc
+++ b/src/tint/builtin/access_test.cc
@@ -15,19 +15,20 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/access_test.cc.tmpl
+//   src/tint/builtin/access_test.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/access.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/type/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 namespace parse_print_tests {
@@ -79,4 +80,4 @@
 }  // namespace parse_print_tests
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/access_test.cc.tmpl b/src/tint/builtin/access_test.cc.tmpl
similarity index 84%
rename from src/tint/type/access_test.cc.tmpl
rename to src/tint/builtin/access_test.cc.tmpl
index dd6ed44..0674f4b 100644
--- a/src/tint/type/access_test.cc.tmpl
+++ b/src/tint/builtin/access_test.cc.tmpl
@@ -14,17 +14,18 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "access") -}}
 
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/access.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/type/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "TestParsePrintEnum" $enum}}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/address_space.cc b/src/tint/builtin/address_space.cc
similarity index 87%
rename from src/tint/type/address_space.cc
rename to src/tint/builtin/address_space.cc
index c8d9e82..3b386b8 100644
--- a/src/tint/type/address_space.cc
+++ b/src/tint/builtin/address_space.cc
@@ -15,19 +15,25 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/address_space.cc.tmpl
+//   src/tint/builtin/address_space.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/address_space.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// ParseAddressSpace parses a AddressSpace from a string.
 /// @param str the string to parse
 /// @returns the parsed enum, or AddressSpace::kUndefined if the string could not be parsed.
 AddressSpace ParseAddressSpace(std::string_view str) {
+    if (str == "__in") {
+        return AddressSpace::kIn;
+    }
+    if (str == "__out") {
+        return AddressSpace::kOut;
+    }
     if (str == "function") {
         return AddressSpace::kFunction;
     }
@@ -53,16 +59,14 @@
     switch (value) {
         case AddressSpace::kUndefined:
             return out << "undefined";
+        case AddressSpace::kIn:
+            return out << "__in";
+        case AddressSpace::kOut:
+            return out << "__out";
         case AddressSpace::kFunction:
             return out << "function";
         case AddressSpace::kHandle:
             return out << "handle";
-        case AddressSpace::kIn:
-            return out << "in";
-        case AddressSpace::kNone:
-            return out << "none";
-        case AddressSpace::kOut:
-            return out << "out";
         case AddressSpace::kPrivate:
             return out << "private";
         case AddressSpace::kPushConstant:
@@ -77,4 +81,4 @@
     return out << "<unknown>";
 }
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/address_space.cc.tmpl b/src/tint/builtin/address_space.cc.tmpl
similarity index 85%
rename from src/tint/type/address_space.cc.tmpl
rename to src/tint/builtin/address_space.cc.tmpl
index f9036b7..a137718 100644
--- a/src/tint/type/address_space.cc.tmpl
+++ b/src/tint/builtin/address_space.cc.tmpl
@@ -14,12 +14,12 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "address_space") -}}
 
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/address_space.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 {{ Eval "ParseEnum" $enum}}
 
 {{ Eval "EnumOStream" $enum}}
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/address_space.h b/src/tint/builtin/address_space.h
similarity index 81%
rename from src/tint/type/address_space.h
rename to src/tint/builtin/address_space.h
index 9b70ea5..55b1557 100644
--- a/src/tint/type/address_space.h
+++ b/src/tint/builtin/address_space.h
@@ -15,26 +15,25 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/address_space.h.tmpl
+//   src/tint/builtin/address_space.h.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#ifndef SRC_TINT_TYPE_ADDRESS_SPACE_H_
-#define SRC_TINT_TYPE_ADDRESS_SPACE_H_
+#ifndef SRC_TINT_BUILTIN_ADDRESS_SPACE_H_
+#define SRC_TINT_BUILTIN_ADDRESS_SPACE_H_
 
 #include <ostream>
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// Address space of a given pointer.
 enum class AddressSpace {
     kUndefined,
+    kIn,
+    kOut,
     kFunction,
     kHandle,  // Tint-internal enum entry - not parsed
-    kIn,      // Tint-internal enum entry - not parsed
-    kNone,    // Tint-internal enum entry - not parsed
-    kOut,     // Tint-internal enum entry - not parsed
     kPrivate,
     kPushConstant,
     kStorage,
@@ -53,7 +52,7 @@
 AddressSpace ParseAddressSpace(std::string_view str);
 
 constexpr const char* kAddressSpaceStrings[] = {
-    "function", "private", "push_constant", "storage", "uniform", "workgroup",
+    "__in", "__out", "function", "private", "push_constant", "storage", "uniform", "workgroup",
 };
 
 /// @returns true if the AddressSpace is host-shareable
@@ -64,6 +63,6 @@
            address_space == AddressSpace::kPushConstant;
 }
 
-}  // namespace tint::type
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_TYPE_ADDRESS_SPACE_H_
+#endif  // SRC_TINT_BUILTIN_ADDRESS_SPACE_H_
diff --git a/src/tint/type/address_space.h.tmpl b/src/tint/builtin/address_space.h.tmpl
similarity index 84%
rename from src/tint/type/address_space.h.tmpl
rename to src/tint/builtin/address_space.h.tmpl
index 70e308a..1dd7d35 100644
--- a/src/tint/type/address_space.h.tmpl
+++ b/src/tint/builtin/address_space.h.tmpl
@@ -14,12 +14,12 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "address_space") -}}
 
-#ifndef SRC_TINT_TYPE_ADDRESS_SPACE_H_
-#define SRC_TINT_TYPE_ADDRESS_SPACE_H_
+#ifndef SRC_TINT_BUILTIN_ADDRESS_SPACE_H_
+#define SRC_TINT_BUILTIN_ADDRESS_SPACE_H_
 
 #include <ostream>
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// Address space of a given pointer.
 {{ Eval "DeclareEnum" $enum}}
@@ -33,6 +33,6 @@
            address_space == AddressSpace::kPushConstant;
 }
 
-}  // namespace tint::type
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_TYPE_ADDRESS_SPACE_H_
+#endif  // SRC_TINT_BUILTIN_ADDRESS_SPACE_H_
diff --git a/src/tint/builtin/address_space_bench.cc b/src/tint/builtin/address_space_bench.cc
new file mode 100644
index 0000000..18cc9d2
--- /dev/null
+++ b/src/tint/builtin/address_space_bench.cc
@@ -0,0 +1,102 @@
+// Copyright 2022 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/address_space_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/address_space.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::builtin {
+namespace {
+
+void AddressSpaceParser(::benchmark::State& state) {
+    const char* kStrings[] = {
+        "ccin",
+        "3",
+        "_Vin",
+        "__in",
+        "1_in",
+        "_qiJ",
+        "_lli77",
+        "__qHupp",
+        "vt",
+        "G_bt",
+        "__out",
+        "__viut",
+        "__8WWt",
+        "Mxxou",
+        "fuXggton",
+        "fuXtou",
+        "funct3on",
+        "function",
+        "funEtion",
+        "PPncTTion",
+        "xxuncddon",
+        "p44ivate",
+        "prSSvaVVe",
+        "RriR22e",
+        "private",
+        "pFva9e",
+        "priate",
+        "VOORRHte",
+        "push_constyn",
+        "punnh_crr77stallt",
+        "pu4h_cons00ant",
+        "push_constant",
+        "puoo_costan",
+        "ushzzcnstant",
+        "push_coii11apt",
+        "storaXXe",
+        "9II5tnnrage",
+        "stoaSSrHHYe",
+        "storage",
+        "stkke",
+        "jtogRa",
+        "sbrag",
+        "unifojm",
+        "niform",
+        "qform",
+        "uniform",
+        "uniNNrm",
+        "nifrvv",
+        "QQiform",
+        "workrorf",
+        "workjroup",
+        "wNNorkrou2",
+        "workgroup",
+        "workgrop",
+        "rrorkgroup",
+        "workgroGp",
+    };
+    for (auto _ : state) {
+        for (auto* str : kStrings) {
+            auto result = ParseAddressSpace(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK(AddressSpaceParser);
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/type/address_space_bench.cc.tmpl b/src/tint/builtin/address_space_bench.cc.tmpl
similarity index 86%
rename from src/tint/type/address_space_bench.cc.tmpl
rename to src/tint/builtin/address_space_bench.cc.tmpl
index 554b2b2..34f7869 100644
--- a/src/tint/type/address_space_bench.cc.tmpl
+++ b/src/tint/builtin/address_space_bench.cc.tmpl
@@ -14,16 +14,16 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "address_space") -}}
 
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/address_space.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" $enum }}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/address_space_test.cc b/src/tint/builtin/address_space_test.cc
similarity index 67%
rename from src/tint/type/address_space_test.cc
rename to src/tint/builtin/address_space_test.cc
index 8b2af5c..1ca7023 100644
--- a/src/tint/type/address_space_test.cc
+++ b/src/tint/builtin/address_space_test.cc
@@ -15,19 +15,20 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/address_space_test.cc.tmpl
+//   src/tint/builtin/address_space_test.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/address_space.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/type/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 namespace parse_print_tests {
@@ -42,6 +43,8 @@
 }
 
 static constexpr Case kValidCases[] = {
+    {"__in", AddressSpace::kIn},
+    {"__out", AddressSpace::kOut},
     {"function", AddressSpace::kFunction},
     {"private", AddressSpace::kPrivate},
     {"push_constant", AddressSpace::kPushConstant},
@@ -51,15 +54,18 @@
 };
 
 static constexpr Case kInvalidCases[] = {
-    {"fccnctin", AddressSpace::kUndefined},        {"ucti3", AddressSpace::kUndefined},
-    {"functVon", AddressSpace::kUndefined},        {"priv1te", AddressSpace::kUndefined},
-    {"pqiJate", AddressSpace::kUndefined},         {"privat7ll", AddressSpace::kUndefined},
-    {"pqqsh_pponstHnt", AddressSpace::kUndefined}, {"pus_cnstat", AddressSpace::kUndefined},
-    {"bus_Gonstant", AddressSpace::kUndefined},    {"storiive", AddressSpace::kUndefined},
-    {"8WWorage", AddressSpace::kUndefined},        {"sxxrage", AddressSpace::kUndefined},
-    {"uXforgg", AddressSpace::kUndefined},         {"nfoXm", AddressSpace::kUndefined},
-    {"unif3rm", AddressSpace::kUndefined},         {"workgroEp", AddressSpace::kUndefined},
-    {"woTTPkroup", AddressSpace::kUndefined},      {"ddorkroxxp", AddressSpace::kUndefined},
+    {"ccin", AddressSpace::kUndefined},          {"3", AddressSpace::kUndefined},
+    {"_Vin", AddressSpace::kUndefined},          {"__ou1", AddressSpace::kUndefined},
+    {"qq_Jt", AddressSpace::kUndefined},         {"__oll7t", AddressSpace::kUndefined},
+    {"qquntppHon", AddressSpace::kUndefined},    {"cnciv", AddressSpace::kUndefined},
+    {"funGion", AddressSpace::kUndefined},       {"priviive", AddressSpace::kUndefined},
+    {"8WWivate", AddressSpace::kUndefined},      {"pxxvate", AddressSpace::kUndefined},
+    {"pXh_cggnstant", AddressSpace::kUndefined}, {"pX_Vonstanu", AddressSpace::kUndefined},
+    {"push_consta3t", AddressSpace::kUndefined}, {"Etorage", AddressSpace::kUndefined},
+    {"sPTTrage", AddressSpace::kUndefined},      {"storadxx", AddressSpace::kUndefined},
+    {"u44iform", AddressSpace::kUndefined},      {"unSSfoVVm", AddressSpace::kUndefined},
+    {"RniR22m", AddressSpace::kUndefined},       {"w9rFroup", AddressSpace::kUndefined},
+    {"workgoup", AddressSpace::kUndefined},      {"woVROOrHup", AddressSpace::kUndefined},
 };
 
 using AddressSpaceParseTest = testing::TestWithParam<Case>;
@@ -86,4 +92,4 @@
 }  // namespace parse_print_tests
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/address_space_test.cc.tmpl b/src/tint/builtin/address_space_test.cc.tmpl
similarity index 83%
rename from src/tint/type/address_space_test.cc.tmpl
rename to src/tint/builtin/address_space_test.cc.tmpl
index 75f16f2..5f7a437 100644
--- a/src/tint/type/address_space_test.cc.tmpl
+++ b/src/tint/builtin/address_space_test.cc.tmpl
@@ -14,17 +14,18 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "address_space") -}}
 
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/address_space.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/type/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "TestParsePrintEnum" $enum}}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/attribute.cc b/src/tint/builtin/attribute.cc
new file mode 100644
index 0000000..d20b77c
--- /dev/null
+++ b/src/tint/builtin/attribute.cc
@@ -0,0 +1,117 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/attribute.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/attribute.h"
+
+namespace tint::builtin {
+
+/// ParseAttribute parses a Attribute from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or Attribute::kUndefined if the string could not be parsed.
+Attribute ParseAttribute(std::string_view str) {
+    if (str == "align") {
+        return Attribute::kAlign;
+    }
+    if (str == "binding") {
+        return Attribute::kBinding;
+    }
+    if (str == "builtin") {
+        return Attribute::kBuiltin;
+    }
+    if (str == "compute") {
+        return Attribute::kCompute;
+    }
+    if (str == "diagnostic") {
+        return Attribute::kDiagnostic;
+    }
+    if (str == "fragment") {
+        return Attribute::kFragment;
+    }
+    if (str == "group") {
+        return Attribute::kGroup;
+    }
+    if (str == "id") {
+        return Attribute::kId;
+    }
+    if (str == "interpolate") {
+        return Attribute::kInterpolate;
+    }
+    if (str == "invariant") {
+        return Attribute::kInvariant;
+    }
+    if (str == "location") {
+        return Attribute::kLocation;
+    }
+    if (str == "must_use") {
+        return Attribute::kMustUse;
+    }
+    if (str == "size") {
+        return Attribute::kSize;
+    }
+    if (str == "vertex") {
+        return Attribute::kVertex;
+    }
+    if (str == "workgroup_size") {
+        return Attribute::kWorkgroupSize;
+    }
+    return Attribute::kUndefined;
+}
+
+std::ostream& operator<<(std::ostream& out, Attribute value) {
+    switch (value) {
+        case Attribute::kUndefined:
+            return out << "undefined";
+        case Attribute::kAlign:
+            return out << "align";
+        case Attribute::kBinding:
+            return out << "binding";
+        case Attribute::kBuiltin:
+            return out << "builtin";
+        case Attribute::kCompute:
+            return out << "compute";
+        case Attribute::kDiagnostic:
+            return out << "diagnostic";
+        case Attribute::kFragment:
+            return out << "fragment";
+        case Attribute::kGroup:
+            return out << "group";
+        case Attribute::kId:
+            return out << "id";
+        case Attribute::kInterpolate:
+            return out << "interpolate";
+        case Attribute::kInvariant:
+            return out << "invariant";
+        case Attribute::kLocation:
+            return out << "location";
+        case Attribute::kMustUse:
+            return out << "must_use";
+        case Attribute::kSize:
+            return out << "size";
+        case Attribute::kVertex:
+            return out << "vertex";
+        case Attribute::kWorkgroupSize:
+            return out << "workgroup_size";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/type/access.cc.tmpl b/src/tint/builtin/attribute.cc.tmpl
similarity index 70%
copy from src/tint/type/access.cc.tmpl
copy to src/tint/builtin/attribute.cc.tmpl
index b34ff61..dde123a 100644
--- a/src/tint/type/access.cc.tmpl
+++ b/src/tint/builtin/attribute.cc.tmpl
@@ -1,6 +1,6 @@
 {{- /*
 --------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate access.cc
+Template file for use with tools/src/cmd/gen to generate attribute.cc
 
 To update the generated file, run:
     ./tools/run gen
@@ -12,14 +12,14 @@
 */ -}}
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
-{{- $enum := (Sem.Enum "access") -}}
+{{- $enum := (Sem.Enum "attribute") -}}
 
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/attribute.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 {{ Eval "ParseEnum" $enum}}
 
 {{ Eval "EnumOStream" $enum}}
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/attribute.h b/src/tint/builtin/attribute.h
new file mode 100644
index 0000000..bf95458
--- /dev/null
+++ b/src/tint/builtin/attribute.h
@@ -0,0 +1,72 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/attribute.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_BUILTIN_ATTRIBUTE_H_
+#define SRC_TINT_BUILTIN_ATTRIBUTE_H_
+
+#include <ostream>
+
+/// \cond DO_NOT_DOCUMENT
+/// There is a bug in doxygen where this enum conflicts with the ast::Attribute
+/// and generates invalid documentation errors.
+namespace tint::builtin {
+
+/// Address space of a given pointer.
+enum class Attribute {
+    kUndefined,
+    kAlign,
+    kBinding,
+    kBuiltin,
+    kCompute,
+    kDiagnostic,
+    kFragment,
+    kGroup,
+    kId,
+    kInterpolate,
+    kInvariant,
+    kLocation,
+    kMustUse,
+    kSize,
+    kVertex,
+    kWorkgroupSize,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the Attribute
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, Attribute value);
+
+/// ParseAttribute parses a Attribute from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or Attribute::kUndefined if the string could not be parsed.
+Attribute ParseAttribute(std::string_view str);
+
+constexpr const char* kAttributeStrings[] = {
+    "align",    "binding",  "builtin", "compute",     "diagnostic",
+    "fragment", "group",    "id",      "interpolate", "invariant",
+    "location", "must_use", "size",    "vertex",      "workgroup_size",
+};
+
+}  // namespace tint::builtin
+/// \endcond
+
+#endif  // SRC_TINT_BUILTIN_ATTRIBUTE_H_
diff --git a/src/tint/builtin/attribute.h.tmpl b/src/tint/builtin/attribute.h.tmpl
new file mode 100644
index 0000000..32ca6a3
--- /dev/null
+++ b/src/tint/builtin/attribute.h.tmpl
@@ -0,0 +1,33 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate attribute.h
+
+To update the generated file, run:
+    ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "attribute") -}}
+
+#ifndef SRC_TINT_BUILTIN_ATTRIBUTE_H_
+#define SRC_TINT_BUILTIN_ATTRIBUTE_H_
+
+#include <ostream>
+
+/// \cond DO_NOT_DOCUMENT
+/// There is a bug in doxygen where this enum conflicts with the ast::Attribute
+/// and generates invalid documentation errors.
+namespace tint::builtin {
+
+/// Address space of a given pointer.
+{{ Eval "DeclareEnum" $enum}}
+
+}  // namespace tint::builtin
+/// \endcond
+
+#endif  // SRC_TINT_BUILTIN_ATTRIBUTE_H_
diff --git a/src/tint/builtin/attribute_bench.cc b/src/tint/builtin/attribute_bench.cc
new file mode 100644
index 0000000..5d12ab3
--- /dev/null
+++ b/src/tint/builtin/attribute_bench.cc
@@ -0,0 +1,151 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/attribute_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/attribute.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::builtin {
+namespace {
+
+void AttributeParser(::benchmark::State& state) {
+    const char* kStrings[] = {
+        "alccn",
+        "3g",
+        "aVign",
+        "align",
+        "alig1",
+        "qqlJn",
+        "alill7n",
+        "ppqqndnHH",
+        "bicv",
+        "bndiGg",
+        "binding",
+        "bindiivg",
+        "8WWnding",
+        "bxxding",
+        "bXltigg",
+        "ultXn",
+        "buil3in",
+        "builtin",
+        "Euiltin",
+        "bPTTltin",
+        "builtdxx",
+        "c44mpute",
+        "coSSpuVVe",
+        "RomR22e",
+        "compute",
+        "cFpu9e",
+        "comute",
+        "VOORRHte",
+        "dyagnstic",
+        "d77agnnnsllrrc",
+        "dia400ostic",
+        "diagnostic",
+        "danstooc",
+        "dignszzic",
+        "d11ansppiic",
+        "XXragment",
+        "fIIa9955nnnt",
+        "aarHHgmenYSS",
+        "fragment",
+        "fkkaet",
+        "gjamRRn",
+        "fabmnt",
+        "gjoup",
+        "goup",
+        "goq",
+        "group",
+        "Nroup",
+        "govv",
+        "gruQQ",
+        "r",
+        "jd",
+        "NNw",
+        "id",
+        "i",
+        "rrd",
+        "iG",
+        "FFnterpolate",
+        "iEtrplat",
+        "inerporrate",
+        "interpolate",
+        "inteplate",
+        "XterJJoDate",
+        "inepol8t",
+        "nvark1n",
+        "invriant",
+        "Jnvarant",
+        "invariant",
+        "invaricnt",
+        "invariaOt",
+        "invttKK_ianvv",
+        "lxxcati8",
+        "Focqq__o",
+        "locaiqqn",
+        "location",
+        "loc33tio6",
+        "ltto6at9QQn",
+        "loc66tio",
+        "mOxt_u6zz",
+        "musyy_use",
+        "mHH_use",
+        "must_use",
+        "qWW4st_se",
+        "musOO_se",
+        "ust_uYe",
+        "i",
+        "Fie",
+        "siw",
+        "size",
+        "zff",
+        "sizqK",
+        "s3zmm",
+        "ertex",
+        "vereq",
+        "vbtbbx",
+        "vertex",
+        "irtex",
+        "vOOteq",
+        "vertTvvx",
+        "woFFkgroup_size",
+        "wfr00grPupsiQe",
+        "workgrouP_size",
+        "workgroup_size",
+        "workgroup77sise",
+        "RRobbkgroupCsize",
+        "wXXrkgroup_size",
+    };
+    for (auto _ : state) {
+        for (auto* str : kStrings) {
+            auto result = ParseAttribute(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK(AttributeParser);
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/type/address_space_bench.cc.tmpl b/src/tint/builtin/attribute_bench.cc.tmpl
similarity index 71%
copy from src/tint/type/address_space_bench.cc.tmpl
copy to src/tint/builtin/attribute_bench.cc.tmpl
index 554b2b2..8f65de0 100644
--- a/src/tint/type/address_space_bench.cc.tmpl
+++ b/src/tint/builtin/attribute_bench.cc.tmpl
@@ -1,6 +1,6 @@
 {{- /*
 --------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate address_space_bench.cc
+Template file for use with tools/src/cmd/gen to generate attribute_bench.cc
 
 To update the generated file, run:
     ./tools/run gen
@@ -12,18 +12,18 @@
 */ -}}
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
-{{- $enum := (Sem.Enum "address_space") -}}
+{{- $enum := (Sem.Enum "attribute") -}}
 
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/attribute.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" $enum }}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/attribute_test.cc b/src/tint/builtin/attribute_test.cc
new file mode 100644
index 0000000..9919467
--- /dev/null
+++ b/src/tint/builtin/attribute_test.cc
@@ -0,0 +1,135 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/attribute_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/attribute.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    Attribute value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"align", Attribute::kAlign},
+    {"binding", Attribute::kBinding},
+    {"builtin", Attribute::kBuiltin},
+    {"compute", Attribute::kCompute},
+    {"diagnostic", Attribute::kDiagnostic},
+    {"fragment", Attribute::kFragment},
+    {"group", Attribute::kGroup},
+    {"id", Attribute::kId},
+    {"interpolate", Attribute::kInterpolate},
+    {"invariant", Attribute::kInvariant},
+    {"location", Attribute::kLocation},
+    {"must_use", Attribute::kMustUse},
+    {"size", Attribute::kSize},
+    {"vertex", Attribute::kVertex},
+    {"workgroup_size", Attribute::kWorkgroupSize},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"alccn", Attribute::kUndefined},
+    {"3g", Attribute::kUndefined},
+    {"aVign", Attribute::kUndefined},
+    {"bind1ng", Attribute::kUndefined},
+    {"bqnJing", Attribute::kUndefined},
+    {"bindin7ll", Attribute::kUndefined},
+    {"ppqqiliHH", Attribute::kUndefined},
+    {"bucv", Attribute::kUndefined},
+    {"biltGn", Attribute::kUndefined},
+    {"compiive", Attribute::kUndefined},
+    {"8WWmpute", Attribute::kUndefined},
+    {"cxxpute", Attribute::kUndefined},
+    {"dXagnosigg", Attribute::kUndefined},
+    {"dagnXuVc", Attribute::kUndefined},
+    {"diagnosti3", Attribute::kUndefined},
+    {"fraEment", Attribute::kUndefined},
+    {"PPagTTent", Attribute::kUndefined},
+    {"xxragddnt", Attribute::kUndefined},
+    {"g44oup", Attribute::kUndefined},
+    {"grVVSSp", Attribute::kUndefined},
+    {"22RRp", Attribute::kUndefined},
+    {"d", Attribute::kUndefined},
+    {"i", Attribute::kUndefined},
+    {"OVd", Attribute::kUndefined},
+    {"inyerpolae", Attribute::kUndefined},
+    {"rrnterpolll77Ge", Attribute::kUndefined},
+    {"inte4pol00te", Attribute::kUndefined},
+    {"inoornt", Attribute::kUndefined},
+    {"inzzriat", Attribute::kUndefined},
+    {"n11pariiin", Attribute::kUndefined},
+    {"XXocation", Attribute::kUndefined},
+    {"lIIc9955nnon", Attribute::kUndefined},
+    {"aaoHHatioYSS", Attribute::kUndefined},
+    {"mkksue", Attribute::kUndefined},
+    {"gjs_RRs", Attribute::kUndefined},
+    {"msb_se", Attribute::kUndefined},
+    {"jize", Attribute::kUndefined},
+    {"sze", Attribute::kUndefined},
+    {"qz", Attribute::kUndefined},
+    {"vNNtex", Attribute::kUndefined},
+    {"vevvx", Attribute::kUndefined},
+    {"veQQex", Attribute::kUndefined},
+    {"workgrrupffie", Attribute::kUndefined},
+    {"workgroup_sije", Attribute::kUndefined},
+    {"workgoupNNwsiz8", Attribute::kUndefined},
+};
+
+using AttributeParseTest = testing::TestWithParam<Case>;
+
+TEST_P(AttributeParseTest, Parse) {
+    const char* string = GetParam().string;
+    Attribute expect = GetParam().value;
+    EXPECT_EQ(expect, ParseAttribute(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, AttributeParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, AttributeParseTest, testing::ValuesIn(kInvalidCases));
+
+using AttributePrintTest = testing::TestWithParam<Case>;
+
+TEST_P(AttributePrintTest, Print) {
+    Attribute value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, AttributePrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/type/access_test.cc.tmpl b/src/tint/builtin/attribute_test.cc.tmpl
similarity index 69%
copy from src/tint/type/access_test.cc.tmpl
copy to src/tint/builtin/attribute_test.cc.tmpl
index dd6ed44..27dd8a9 100644
--- a/src/tint/type/access_test.cc.tmpl
+++ b/src/tint/builtin/attribute_test.cc.tmpl
@@ -1,6 +1,6 @@
 {{- /*
 --------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate access_test.cc
+Template file for use with tools/src/cmd/gen to generate attribute_test.cc
 
 To update the generated file, run:
     ./tools/run gen
@@ -12,19 +12,20 @@
 */ -}}
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
-{{- $enum := (Sem.Enum "access") -}}
+{{- $enum := (Sem.Enum "attribute") -}}
 
-#include "src/tint/type/access.h"
+#include "src/tint/builtin/attribute.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/type/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "TestParsePrintEnum" $enum}}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/builtin.cc b/src/tint/builtin/builtin.cc
similarity index 98%
rename from src/tint/type/builtin.cc
rename to src/tint/builtin/builtin.cc
index 828bf57..60449b5 100644
--- a/src/tint/type/builtin.cc
+++ b/src/tint/builtin/builtin.cc
@@ -15,14 +15,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/builtin.cc.tmpl
+//   src/tint/builtin/builtin.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/builtin.h"
+#include "src/tint/builtin/builtin.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// ParseBuiltin parses a Builtin from a string.
 /// @param str the string to parse
@@ -384,4 +384,4 @@
     return out << "<unknown>";
 }
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/builtin.cc.tmpl b/src/tint/builtin/builtin.cc.tmpl
similarity index 87%
rename from src/tint/type/builtin.cc.tmpl
rename to src/tint/builtin/builtin.cc.tmpl
index a790224..b5dd5ae 100644
--- a/src/tint/type/builtin.cc.tmpl
+++ b/src/tint/builtin/builtin.cc.tmpl
@@ -15,12 +15,12 @@
 {{- $enum := (Sem.Enum "builtin_type") -}}
 {{- Eval "OverrideEnumName" "Enum" $enum "Name" "Builtin" -}}
 
-#include "src/tint/type/builtin.h"
+#include "src/tint/builtin/builtin.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 {{ Eval "ParseEnum" $enum}}
 
 {{ Eval "EnumOStream" $enum}}
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/builtin.h b/src/tint/builtin/builtin.h
similarity index 93%
rename from src/tint/type/builtin.h
rename to src/tint/builtin/builtin.h
index 78e63c2..f514109 100644
--- a/src/tint/type/builtin.h
+++ b/src/tint/builtin/builtin.h
@@ -15,19 +15,19 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/builtin.h.tmpl
+//   src/tint/builtin/builtin.h.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#ifndef SRC_TINT_TYPE_BUILTIN_H_
-#define SRC_TINT_TYPE_BUILTIN_H_
+#ifndef SRC_TINT_BUILTIN_BUILTIN_H_
+#define SRC_TINT_BUILTIN_BUILTIN_H_
 
 #include <ostream>
 
-namespace tint::type {
+namespace tint::builtin {
 
-/// An enumerator of builtin types.
+/// An enumerator of builtin builtin.
 enum class Builtin {
     kUndefined,
     kArray,
@@ -183,6 +183,6 @@
     "vec4u",
 };
 
-}  // namespace tint::type
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_TYPE_BUILTIN_H_
+#endif  // SRC_TINT_BUILTIN_BUILTIN_H_
diff --git a/src/tint/type/builtin.h.tmpl b/src/tint/builtin/builtin.h.tmpl
similarity index 76%
rename from src/tint/type/builtin.h.tmpl
rename to src/tint/builtin/builtin.h.tmpl
index 4067bb4..4fce648 100644
--- a/src/tint/type/builtin.h.tmpl
+++ b/src/tint/builtin/builtin.h.tmpl
@@ -15,16 +15,16 @@
 {{- $enum := (Sem.Enum "builtin_type") -}}
 {{- Eval "OverrideEnumName" "Enum" $enum "Name" "Builtin" -}}
 
-#ifndef SRC_TINT_TYPE_BUILTIN_H_
-#define SRC_TINT_TYPE_BUILTIN_H_
+#ifndef SRC_TINT_BUILTIN_BUILTIN_H_
+#define SRC_TINT_BUILTIN_BUILTIN_H_
 
 #include <ostream>
 
-namespace tint::type {
+namespace tint::builtin {
 
-/// An enumerator of builtin types.
+/// An enumerator of builtin builtin.
 {{ Eval "DeclareEnum" $enum}}
 
-}  // namespace tint::type
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_TYPE_BUILTIN_H_
+#endif  // SRC_TINT_BUILTIN_BUILTIN_H_
diff --git a/src/tint/type/builtin_bench.cc b/src/tint/builtin/builtin_bench.cc
similarity index 98%
rename from src/tint/type/builtin_bench.cc
rename to src/tint/builtin/builtin_bench.cc
index f8b86cf..3c3134d 100644
--- a/src/tint/type/builtin_bench.cc
+++ b/src/tint/builtin/builtin_bench.cc
@@ -15,18 +15,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/builtin_bench.cc.tmpl
+//   src/tint/builtin/builtin_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/builtin.h"
+#include "src/tint/builtin/builtin.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 void BuiltinParser(::benchmark::State& state) {
@@ -526,4 +526,4 @@
 BENCHMARK(BuiltinParser);
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/builtin_bench.cc.tmpl b/src/tint/builtin/builtin_bench.cc.tmpl
similarity index 88%
rename from src/tint/type/builtin_bench.cc.tmpl
rename to src/tint/builtin/builtin_bench.cc.tmpl
index e2cd475..1f56c40 100644
--- a/src/tint/type/builtin_bench.cc.tmpl
+++ b/src/tint/builtin/builtin_bench.cc.tmpl
@@ -15,16 +15,16 @@
 {{- $enum := (Sem.Enum "builtin_type") -}}
 {{- Eval "OverrideEnumName" "Enum" $enum "Name" "Builtin" -}}
 
-#include "src/tint/type/builtin.h"
+#include "src/tint/builtin/builtin.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" $enum }}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/builtin_test.cc b/src/tint/builtin/builtin_test.cc
similarity index 98%
rename from src/tint/type/builtin_test.cc
rename to src/tint/builtin/builtin_test.cc
index 345a214..2908bc2 100644
--- a/src/tint/type/builtin_test.cc
+++ b/src/tint/builtin/builtin_test.cc
@@ -15,12 +15,12 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/builtin_test.cc.tmpl
+//   src/tint/builtin/builtin_test.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/builtin.h"
+#include "src/tint/builtin/builtin.h"
 
 #include <string>
 
@@ -28,7 +28,7 @@
 
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 namespace parse_print_tests {
@@ -348,4 +348,4 @@
 }  // namespace parse_print_tests
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/builtin_test.cc.tmpl b/src/tint/builtin/builtin_test.cc.tmpl
similarity index 88%
rename from src/tint/type/builtin_test.cc.tmpl
rename to src/tint/builtin/builtin_test.cc.tmpl
index bf84fba..721671f 100644
--- a/src/tint/type/builtin_test.cc.tmpl
+++ b/src/tint/builtin/builtin_test.cc.tmpl
@@ -15,7 +15,7 @@
 {{- $enum := (Sem.Enum "builtin_type") -}}
 {{- Eval "OverrideEnumName" "Enum" $enum "Name" "Builtin" -}}
 
-#include "src/tint/type/builtin.h"
+#include "src/tint/builtin/builtin.h"
 
 #include <string>
 
@@ -23,10 +23,10 @@
 
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "TestParsePrintEnum" $enum}}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/builtin_value.cc b/src/tint/builtin/builtin_value.cc
index 740ebcc..150ac7b 100644
--- a/src/tint/builtin/builtin_value.cc
+++ b/src/tint/builtin/builtin_value.cc
@@ -28,6 +28,9 @@
 /// @param str the string to parse
 /// @returns the parsed enum, or BuiltinValue::kUndefined if the string could not be parsed.
 BuiltinValue ParseBuiltinValue(std::string_view str) {
+    if (str == "__point_size") {
+        return BuiltinValue::kPointSize;
+    }
     if (str == "frag_depth") {
         return BuiltinValue::kFragDepth;
     }
@@ -71,6 +74,8 @@
     switch (value) {
         case BuiltinValue::kUndefined:
             return out << "undefined";
+        case BuiltinValue::kPointSize:
+            return out << "__point_size";
         case BuiltinValue::kFragDepth:
             return out << "frag_depth";
         case BuiltinValue::kFrontFacing:
@@ -85,8 +90,6 @@
             return out << "local_invocation_index";
         case BuiltinValue::kNumWorkgroups:
             return out << "num_workgroups";
-        case BuiltinValue::kPointSize:
-            return out << "point_size";
         case BuiltinValue::kPosition:
             return out << "position";
         case BuiltinValue::kSampleIndex:
diff --git a/src/tint/builtin/builtin_value.h b/src/tint/builtin/builtin_value.h
index 1d5b4d4..4f8753f 100644
--- a/src/tint/builtin/builtin_value.h
+++ b/src/tint/builtin/builtin_value.h
@@ -30,6 +30,7 @@
 /// Builtin value defined with `@builtin(<name>)`.
 enum class BuiltinValue {
     kUndefined,
+    kPointSize,
     kFragDepth,
     kFrontFacing,
     kGlobalInvocationId,
@@ -37,7 +38,6 @@
     kLocalInvocationId,
     kLocalInvocationIndex,
     kNumWorkgroups,
-    kPointSize,  // Tint-internal enum entry - not parsed
     kPosition,
     kSampleIndex,
     kSampleMask,
@@ -56,12 +56,11 @@
 BuiltinValue ParseBuiltinValue(std::string_view str);
 
 constexpr const char* kBuiltinValueStrings[] = {
-    "frag_depth",           "front_facing",
-    "global_invocation_id", "instance_index",
-    "local_invocation_id",  "local_invocation_index",
-    "num_workgroups",       "position",
-    "sample_index",         "sample_mask",
-    "vertex_index",         "workgroup_id",
+    "__point_size",           "frag_depth",     "front_facing",
+    "global_invocation_id",   "instance_index", "local_invocation_id",
+    "local_invocation_index", "num_workgroups", "position",
+    "sample_index",           "sample_mask",    "vertex_index",
+    "workgroup_id",
 };
 
 }  // namespace tint::builtin
diff --git a/src/tint/builtin/builtin_value_bench.cc b/src/tint/builtin/builtin_value_bench.cc
index 50d677e..4d2e562 100644
--- a/src/tint/builtin/builtin_value_bench.cc
+++ b/src/tint/builtin/builtin_value_bench.cc
@@ -31,90 +31,97 @@
 
 void BuiltinValueParser(::benchmark::State& state) {
     const char* kStrings[] = {
-        "fragdeccth",
-        "flaget3",
-        "fVag_depth",
+        "_ccpoint_siz",
+        "_3poi_ile",
+        "__poiVt_size",
+        "__point_size",
+        "1_point_size",
+        "__pointJsqze",
+        "__lloint_siz77",
+        "frqqgppepHHh",
+        "fv_dcpt",
+        "frabGdeth",
         "frag_depth",
-        "frag1depth",
-        "fraJqqepth",
-        "fra7ll_depth",
-        "fonHHpp_facing",
-        "fron_facg",
-        "frGnt_fbcin",
+        "frag_veiith",
+        "fr8g_depWWh",
+        "Mragxxepth",
+        "ggroXtfacing",
+        "Vot_fuciXg",
+        "front_fac3ng",
         "front_facing",
-        "front_facvnii",
-        "frWWnt_faci8g",
-        "fxxonM_facig",
-        "gXobalgginvocationid",
-        "goVal_uvocatioX_id",
-        "global_in3ocation_id",
+        "front_fEcing",
+        "fronPPfaTTing",
+        "ddroxxtfacing",
+        "global_invocatio44_id",
+        "global_invocaSSioVV_id",
+        "22loRal_invoRtion_id",
         "global_invocation_id",
-        "global_invocation_iE",
-        "TTobal_invocationPPid",
-        "globdd_invocatioxx_id",
-        "instance44index",
-        "instaVVce_SSndex",
-        "Rnstane_ind2Rx",
+        "globalFinvoction_id",
+        "gloal_invocation_id",
+        "RRlHOOaV_invoction_id",
+        "instance_ydex",
+        "instGlr77cnn_index",
+        "instan04e_index",
         "instance_index",
-        "inFtanceind9x",
-        "insance_index",
-        "inRRancV_OOHdex",
-        "local_nvocytion_id",
-        "llGcnnl_inv77catirrn_id",
-        "local_invoca4i00n_id",
+        "insacoo_inex",
+        "izstane_index",
+        "nippance_in11ex",
+        "local_invXXcation_id",
+        "lIIcal_i5599ocation_inn",
+        "HHrrcal_inSSocation_Yaa",
         "local_invocation_id",
-        "loool_nvocaton_id",
-        "local_inozztion_id",
-        "p11cal_invocatiiin_i",
-        "local_invocation_iXXdex",
-        "local_invnnIIati99n55index",
-        "localYirrHHocaationSSindex",
+        "lokkal_invocatini",
+        "jocal_invocRRongid",
+        "local_inocatbon_i",
+        "local_injocation_index",
+        "local_invocatio_index",
+        "locl_invocqtion_ndex",
         "local_invocation_index",
-        "lkkal_invHcation_idx",
-        "gRcal_invocatioj_inex",
-        "lcal_invcbtion_index",
+        "localNNinvocaton_index",
+        "local_invocatin_ivvdx",
+        "locl_invocatioQQ_index",
+        "num_workgffus",
         "num_workgroujs",
-        "num_worgroups",
-        "nuq_orkgoups",
+        "num_wrkgNNwoup8",
         "num_workgroups",
-        "nm_workgroNNps",
-        "um_workgrovps",
-        "nQQm_orkgroups",
-        "posftrn",
-        "pojition",
-        "poswNN82n",
+        "numworkgroups",
+        "num_workrrroups",
+        "num_worGgroups",
+        "pFFsition",
+        "pEiio",
+        "prrsitio",
         "position",
-        "positon",
-        "porrition",
-        "pGsition",
-        "sample_inFFex",
-        "samleinex",
-        "sample_indrr",
+        "sition",
+        "poJJDtin",
+        "poi8i",
+        "smpke11nde",
+        "samle_index",
+        "saple_Jndex",
         "sample_index",
-        "sample_iex",
-        "DaplX_JJndex",
-        "8amleinde",
-        "saplekmak",
-        "samle_mask",
-        "saJple_mak",
+        "cample_index",
+        "sample_indOx",
+        "savvKKl___inttex",
+        "sam8le_xx5k",
+        "sampqq__msk",
+        "sampleqmask",
         "sample_mask",
-        "sample_cask",
-        "sample_maOk",
-        "__attpvve_KKask",
-        "vrtex5inxxe8",
-        "v__rex_qFdex",
-        "veqqtex_idex",
+        "33amOe_mas66",
+        "samoott6QQmask",
+        "66mple_mask",
+        "verzzx_in6Oxx",
+        "vertex_yyndex",
+        "vetxHHZnZex",
         "vertex_index",
-        "veOtx_33nde66",
-        "v6ootex_indttQx",
-        "ver66ex_inex",
-        "worzzroup6Oxd",
-        "workgroyyp_id",
-        "wokrHHZpZid",
+        "vWWteq_in44ex",
+        "vrtex_OOndex",
+        "hrteYooindx",
+        "wogroup_i",
+        "wokgrouF_id",
+        "worgrwup_id",
         "workgroup_id",
-        "wWWkgqoup44id",
-        "wrkgroOOp_id",
-        "hrkgYooup_d",
+        "workGKou_if",
+        "worKKgrouq_id",
+        "w3rkgrommp_id",
     };
     for (auto _ : state) {
         for (auto* str : kStrings) {
diff --git a/src/tint/builtin/builtin_value_test.cc b/src/tint/builtin/builtin_value_test.cc
index b245250..ae615bc 100644
--- a/src/tint/builtin/builtin_value_test.cc
+++ b/src/tint/builtin/builtin_value_test.cc
@@ -43,6 +43,7 @@
 }
 
 static constexpr Case kValidCases[] = {
+    {"__point_size", BuiltinValue::kPointSize},
     {"frag_depth", BuiltinValue::kFragDepth},
     {"front_facing", BuiltinValue::kFrontFacing},
     {"global_invocation_id", BuiltinValue::kGlobalInvocationId},
@@ -58,42 +59,45 @@
 };
 
 static constexpr Case kInvalidCases[] = {
-    {"fragdeccth", BuiltinValue::kUndefined},
-    {"flaget3", BuiltinValue::kUndefined},
-    {"fVag_depth", BuiltinValue::kUndefined},
-    {"1ront_facing", BuiltinValue::kUndefined},
-    {"front_fJcqng", BuiltinValue::kUndefined},
-    {"frllnt_facin77", BuiltinValue::kUndefined},
-    {"global_invoqqtionppHid", BuiltinValue::kUndefined},
-    {"clvbal_inocaionid", BuiltinValue::kUndefined},
-    {"global_Gvocation_id", BuiltinValue::kUndefined},
-    {"invtance_iniiex", BuiltinValue::kUndefined},
-    {"8nstanceWWindex", BuiltinValue::kUndefined},
-    {"insxxanceindex", BuiltinValue::kUndefined},
-    {"lXcal_invoation_igg", BuiltinValue::kUndefined},
-    {"Xocal_nvocatin_Vd", BuiltinValue::kUndefined},
-    {"local_invoca3ion_id", BuiltinValue::kUndefined},
-    {"local_invocation_indeE", BuiltinValue::kUndefined},
-    {"loTTal_invPPcatin_index", BuiltinValue::kUndefined},
-    {"loal_invocadxxion_index", BuiltinValue::kUndefined},
-    {"num_work44roups", BuiltinValue::kUndefined},
-    {"num_wVVrkgSSoups", BuiltinValue::kUndefined},
-    {"Rum_wokgrou2Rs", BuiltinValue::kUndefined},
-    {"oFi9ion", BuiltinValue::kUndefined},
-    {"postion", BuiltinValue::kUndefined},
-    {"ROOoHiiVn", BuiltinValue::kUndefined},
-    {"samply_inde", BuiltinValue::kUndefined},
-    {"snrrmpl77l_indGx", BuiltinValue::kUndefined},
-    {"00ample4index", BuiltinValue::kUndefined},
-    {"smoo_mask", BuiltinValue::kUndefined},
-    {"sampzemask", BuiltinValue::kUndefined},
-    {"ppaplii1_mas", BuiltinValue::kUndefined},
-    {"vertex_iXXdex", BuiltinValue::kUndefined},
-    {"5nnertex_99IIdex", BuiltinValue::kUndefined},
-    {"verYeaaHHrrndeSS", BuiltinValue::kUndefined},
-    {"workkgHo_i", BuiltinValue::kUndefined},
-    {"worRgoupjid", BuiltinValue::kUndefined},
-    {"wrkgrupbid", BuiltinValue::kUndefined},
+    {"_ccpoint_siz", BuiltinValue::kUndefined},
+    {"_3poi_ile", BuiltinValue::kUndefined},
+    {"__poiVt_size", BuiltinValue::kUndefined},
+    {"frag1depth", BuiltinValue::kUndefined},
+    {"fraJqqepth", BuiltinValue::kUndefined},
+    {"fra7ll_depth", BuiltinValue::kUndefined},
+    {"fonHHpp_facing", BuiltinValue::kUndefined},
+    {"fron_facg", BuiltinValue::kUndefined},
+    {"frGnt_fbcin", BuiltinValue::kUndefined},
+    {"glvbal_iinvocation_id", BuiltinValue::kUndefined},
+    {"gl8bal_invocation_WWd", BuiltinValue::kUndefined},
+    {"Mlobal_invocaton_xxd", BuiltinValue::kUndefined},
+    {"isXance_indegg", BuiltinValue::kUndefined},
+    {"insanc_iXVex", BuiltinValue::kUndefined},
+    {"instance_in3ex", BuiltinValue::kUndefined},
+    {"local_Envocation_id", BuiltinValue::kUndefined},
+    {"localiPPvocatioTT_id", BuiltinValue::kUndefined},
+    {"localxxnvocationddid", BuiltinValue::kUndefined},
+    {"loca44_invocation_index", BuiltinValue::kUndefined},
+    {"local_invocSStionVVindex", BuiltinValue::kUndefined},
+    {"locRR_invocat22n_index", BuiltinValue::kUndefined},
+    {"nuF_workrou9s", BuiltinValue::kUndefined},
+    {"numworkgroups", BuiltinValue::kUndefined},
+    {"nuRRworVgOOHups", BuiltinValue::kUndefined},
+    {"posytio", BuiltinValue::kUndefined},
+    {"77orritllnon", BuiltinValue::kUndefined},
+    {"04osition", BuiltinValue::kUndefined},
+    {"smpe_oonde", BuiltinValue::kUndefined},
+    {"smpl_inzzex", BuiltinValue::kUndefined},
+    {"saiip11eindep", BuiltinValue::kUndefined},
+    {"sample_XXask", BuiltinValue::kUndefined},
+    {"samII99l55_mask", BuiltinValue::kUndefined},
+    {"samaale_SSrHHYk", BuiltinValue::kUndefined},
+    {"verkkeH_de", BuiltinValue::kUndefined},
+    {"verRg_injex", BuiltinValue::kUndefined},
+    {"vrtexinbex", BuiltinValue::kUndefined},
+    {"workjroup_id", BuiltinValue::kUndefined},
+    {"wrkgroup_id", BuiltinValue::kUndefined},
+    {"qorkgro_id", BuiltinValue::kUndefined},
 };
 
 using BuiltinValueParseTest = testing::TestWithParam<Case>;
diff --git a/src/tint/builtin/diagnostic_rule.cc b/src/tint/builtin/diagnostic_rule.cc
new file mode 100644
index 0000000..7b020d5
--- /dev/null
+++ b/src/tint/builtin/diagnostic_rule.cc
@@ -0,0 +1,55 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/diagnostic_rule.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/diagnostic_rule.h"
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// ParseDiagnosticRule parses a DiagnosticRule from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or DiagnosticRule::kUndefined if the string could not be parsed.
+DiagnosticRule ParseDiagnosticRule(std::string_view str) {
+    if (str == "chromium_unreachable_code") {
+        return DiagnosticRule::kChromiumUnreachableCode;
+    }
+    if (str == "derivative_uniformity") {
+        return DiagnosticRule::kDerivativeUniformity;
+    }
+    return DiagnosticRule::kUndefined;
+}
+
+std::ostream& operator<<(std::ostream& out, DiagnosticRule value) {
+    switch (value) {
+        case DiagnosticRule::kUndefined:
+            return out << "undefined";
+        case DiagnosticRule::kChromiumUnreachableCode:
+            return out << "chromium_unreachable_code";
+        case DiagnosticRule::kDerivativeUniformity:
+            return out << "derivative_uniformity";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule.cc.tmpl b/src/tint/builtin/diagnostic_rule.cc.tmpl
new file mode 100644
index 0000000..4cf05a4
--- /dev/null
+++ b/src/tint/builtin/diagnostic_rule.cc.tmpl
@@ -0,0 +1,24 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate diagnostic_control.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/diagnostic_rule.h"
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+{{ Eval "ParseEnum" (Sem.Enum "diagnostic_rule")}}
+
+{{ Eval "EnumOStream" (Sem.Enum "diagnostic_rule")}}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule.h b/src/tint/builtin/diagnostic_rule.h
new file mode 100644
index 0000000..55a6aab
--- /dev/null
+++ b/src/tint/builtin/diagnostic_rule.h
@@ -0,0 +1,54 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/diagnostic_rule.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
+#define SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
+
+#include <string>
+
+namespace tint::builtin {
+
+/// The diagnostic rule.
+enum class DiagnosticRule {
+    kUndefined,
+    kChromiumUnreachableCode,
+    kDerivativeUniformity,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the DiagnosticRule
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, DiagnosticRule value);
+
+/// ParseDiagnosticRule parses a DiagnosticRule from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or DiagnosticRule::kUndefined if the string could not be parsed.
+DiagnosticRule ParseDiagnosticRule(std::string_view str);
+
+constexpr const char* kDiagnosticRuleStrings[] = {
+    "chromium_unreachable_code",
+    "derivative_uniformity",
+};
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
diff --git a/src/tint/builtin/diagnostic_rule.h.tmpl b/src/tint/builtin/diagnostic_rule.h.tmpl
new file mode 100644
index 0000000..2e6f7f9
--- /dev/null
+++ b/src/tint/builtin/diagnostic_rule.h.tmpl
@@ -0,0 +1,25 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate diagnostic_control.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#ifndef SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
+#define SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
+
+#include <string>
+
+namespace tint::builtin {
+
+/// The diagnostic rule.
+{{ Eval "DeclareEnum" (Sem.Enum "diagnostic_rule") }}
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
diff --git a/src/tint/builtin/diagnostic_rule_bench.cc b/src/tint/builtin/diagnostic_rule_bench.cc
new file mode 100644
index 0000000..c98bd46
--- /dev/null
+++ b/src/tint/builtin/diagnostic_rule_bench.cc
@@ -0,0 +1,51 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/diagnostic_rule_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/diagnostic_rule.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::builtin {
+namespace {
+
+void DiagnosticRuleParser(::benchmark::State& state) {
+    const char* kStrings[] = {
+        "chromium_unrachaccle_code",   "clromium_unreachab3_oe",    "chromium_unreachable_Vode",
+        "chromium_unreachable_code",   "chro1ium_unreachable_code", "chromium_unreJchableqqcde",
+        "chromium77unreallhable_code", "dqqrvatiHHe_uniforppity",   "deriatcv_nvformity",
+        "derivatbe_unGformity",        "derivative_uniformity",     "derivative_iinifvrmity",
+        "derivat8WWe_uniformity",      "drivaxxive_uniformity",
+    };
+    for (auto _ : state) {
+        for (auto* str : kStrings) {
+            auto result = ParseDiagnosticRule(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK(DiagnosticRuleParser);
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/ast/diagnostic_control_bench.cc.tmpl b/src/tint/builtin/diagnostic_rule_bench.cc.tmpl
similarity index 78%
copy from src/tint/ast/diagnostic_control_bench.cc.tmpl
copy to src/tint/builtin/diagnostic_rule_bench.cc.tmpl
index 55d3cce..2605aae 100644
--- a/src/tint/ast/diagnostic_control_bench.cc.tmpl
+++ b/src/tint/builtin/diagnostic_rule_bench.cc.tmpl
@@ -10,18 +10,16 @@
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 
-#include "src/tint/ast/diagnostic_control.h"
+#include "src/tint/builtin/diagnostic_rule.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
-{{ Eval "BenchmarkParseEnum" (Sem.Enum "diagnostic_severity")}}
-
 {{ Eval "BenchmarkParseEnum" (Sem.Enum "diagnostic_rule")}}
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule_test.cc b/src/tint/builtin/diagnostic_rule_test.cc
new file mode 100644
index 0000000..9982061
--- /dev/null
+++ b/src/tint/builtin/diagnostic_rule_test.cc
@@ -0,0 +1,85 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/diagnostic_rule_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include <string>
+
+#include "gtest/gtest-spi.h"
+#include "src/tint/builtin/diagnostic_rule.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace diagnostic_rule_tests {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    DiagnosticRule value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"chromium_unreachable_code", DiagnosticRule::kChromiumUnreachableCode},
+    {"derivative_uniformity", DiagnosticRule::kDerivativeUniformity},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"chromium_unrachaccle_code", DiagnosticRule::kUndefined},
+    {"clromium_unreachab3_oe", DiagnosticRule::kUndefined},
+    {"chromium_unreachable_Vode", DiagnosticRule::kUndefined},
+    {"derivative_uniform1ty", DiagnosticRule::kUndefined},
+    {"derivativeJunifqrmity", DiagnosticRule::kUndefined},
+    {"derivative_unifllrmit77", DiagnosticRule::kUndefined},
+};
+
+using DiagnosticRuleParseTest = testing::TestWithParam<Case>;
+
+TEST_P(DiagnosticRuleParseTest, Parse) {
+    const char* string = GetParam().string;
+    DiagnosticRule expect = GetParam().value;
+    EXPECT_EQ(expect, ParseDiagnosticRule(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticRuleParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, DiagnosticRuleParseTest, testing::ValuesIn(kInvalidCases));
+
+using DiagnosticRulePrintTest = testing::TestWithParam<Case>;
+
+TEST_P(DiagnosticRulePrintTest, Print) {
+    DiagnosticRule value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticRulePrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace diagnostic_rule_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule_test.cc.tmpl b/src/tint/builtin/diagnostic_rule_test.cc.tmpl
new file mode 100644
index 0000000..106f6fc
--- /dev/null
+++ b/src/tint/builtin/diagnostic_rule_test.cc.tmpl
@@ -0,0 +1,29 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate diagnostic_control_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include <string>
+
+#include "gtest/gtest-spi.h"
+#include "src/tint/builtin/diagnostic_rule.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace diagnostic_rule_tests {
+
+{{ Eval "TestParsePrintEnum" (Sem.Enum "diagnostic_rule")}}
+
+}  // namespace diagnostic_rule_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_severity.cc b/src/tint/builtin/diagnostic_severity.cc
new file mode 100644
index 0000000..8c14a9a
--- /dev/null
+++ b/src/tint/builtin/diagnostic_severity.cc
@@ -0,0 +1,77 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/diagnostic_severity.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/diagnostic_severity.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+diag::Severity ToSeverity(DiagnosticSeverity sc) {
+    switch (sc) {
+        case DiagnosticSeverity::kError:
+            return diag::Severity::Error;
+        case DiagnosticSeverity::kWarning:
+            return diag::Severity::Warning;
+        case DiagnosticSeverity::kInfo:
+            return diag::Severity::Note;
+        default:
+            return diag::Severity::InternalCompilerError;
+    }
+}
+
+/// ParseDiagnosticSeverity parses a DiagnosticSeverity from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or DiagnosticSeverity::kUndefined if the string could not be parsed.
+DiagnosticSeverity ParseDiagnosticSeverity(std::string_view str) {
+    if (str == "error") {
+        return DiagnosticSeverity::kError;
+    }
+    if (str == "info") {
+        return DiagnosticSeverity::kInfo;
+    }
+    if (str == "off") {
+        return DiagnosticSeverity::kOff;
+    }
+    if (str == "warning") {
+        return DiagnosticSeverity::kWarning;
+    }
+    return DiagnosticSeverity::kUndefined;
+}
+
+std::ostream& operator<<(std::ostream& out, DiagnosticSeverity value) {
+    switch (value) {
+        case DiagnosticSeverity::kUndefined:
+            return out << "undefined";
+        case DiagnosticSeverity::kError:
+            return out << "error";
+        case DiagnosticSeverity::kInfo:
+            return out << "info";
+        case DiagnosticSeverity::kOff:
+            return out << "off";
+        case DiagnosticSeverity::kWarning:
+            return out << "warning";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/ast/diagnostic_control.cc.tmpl b/src/tint/builtin/diagnostic_severity.cc.tmpl
similarity index 61%
rename from src/tint/ast/diagnostic_control.cc.tmpl
rename to src/tint/builtin/diagnostic_severity.cc.tmpl
index bfdf86a..3278bb1 100644
--- a/src/tint/ast/diagnostic_control.cc.tmpl
+++ b/src/tint/builtin/diagnostic_severity.cc.tmpl
@@ -10,23 +10,11 @@
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 
-#include "src/tint/ast/diagnostic_control.h"
+#include "src/tint/builtin/diagnostic_severity.h"
 
 #include <string>
 
-#include "src/tint/ast/identifier.h"
-#include "src/tint/ast/templated_identifier.h"
-
-namespace tint::ast {
-
-DiagnosticControl::DiagnosticControl(DiagnosticSeverity sev, const Identifier* rule)
-        : severity(sev), rule_name(rule) {
-    TINT_ASSERT(AST, rule != nullptr);
-    if (rule) {
-        // It is invalid for a diagnostic rule name to be templated
-        TINT_ASSERT(AST, !rule->Is<TemplatedIdentifier>());
-    }
-}
+namespace tint::builtin {
 
 diag::Severity ToSeverity(DiagnosticSeverity sc) {
     switch (sc) {
@@ -45,8 +33,4 @@
 
 {{ Eval "EnumOStream" (Sem.Enum "diagnostic_severity")}}
 
-{{ Eval "ParseEnum" (Sem.Enum "diagnostic_rule")}}
-
-{{ Eval "EnumOStream" (Sem.Enum "diagnostic_rule")}}
-
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_severity.h b/src/tint/builtin/diagnostic_severity.h
new file mode 100644
index 0000000..daef0f7
--- /dev/null
+++ b/src/tint/builtin/diagnostic_severity.h
@@ -0,0 +1,69 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/diagnostic_severity.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_BUILTIN_DIAGNOSTIC_SEVERITY_H_
+#define SRC_TINT_BUILTIN_DIAGNOSTIC_SEVERITY_H_
+
+#include <ostream>
+#include <string>
+#include <unordered_map>
+
+#include "src/tint/builtin/diagnostic_rule.h"
+#include "src/tint/diagnostic/diagnostic.h"
+
+namespace tint::builtin {
+
+/// The diagnostic severity control.
+enum class DiagnosticSeverity {
+    kUndefined,
+    kError,
+    kInfo,
+    kOff,
+    kWarning,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the DiagnosticSeverity
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, DiagnosticSeverity value);
+
+/// ParseDiagnosticSeverity parses a DiagnosticSeverity from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or DiagnosticSeverity::kUndefined if the string could not be parsed.
+DiagnosticSeverity ParseDiagnosticSeverity(std::string_view str);
+
+constexpr const char* kDiagnosticSeverityStrings[] = {
+    "error",
+    "info",
+    "off",
+    "warning",
+};
+
+/// Convert a DiagnosticSeverity to the corresponding diag::Severity.
+diag::Severity ToSeverity(DiagnosticSeverity sc);
+
+/// DiagnosticRuleSeverities is a map from diagnostic rule to diagnostic severity.
+using DiagnosticRuleSeverities = std::unordered_map<DiagnosticRule, DiagnosticSeverity>;
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_DIAGNOSTIC_SEVERITY_H_
diff --git a/src/tint/builtin/diagnostic_severity.h.tmpl b/src/tint/builtin/diagnostic_severity.h.tmpl
new file mode 100644
index 0000000..7580b2c
--- /dev/null
+++ b/src/tint/builtin/diagnostic_severity.h.tmpl
@@ -0,0 +1,36 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate diagnostic_control.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#ifndef SRC_TINT_BUILTIN_DIAGNOSTIC_SEVERITY_H_
+#define SRC_TINT_BUILTIN_DIAGNOSTIC_SEVERITY_H_
+
+#include <ostream>
+#include <string>
+#include <unordered_map>
+
+#include "src/tint/builtin/diagnostic_rule.h"
+#include "src/tint/diagnostic/diagnostic.h"
+
+namespace tint::builtin {
+
+/// The diagnostic severity control.
+{{ Eval "DeclareEnum" (Sem.Enum "diagnostic_severity") }}
+
+/// Convert a DiagnosticSeverity to the corresponding diag::Severity.
+diag::Severity ToSeverity(DiagnosticSeverity sc);
+
+/// DiagnosticRuleSeverities is a map from diagnostic rule to diagnostic severity.
+using DiagnosticRuleSeverities = std::unordered_map<DiagnosticRule, DiagnosticSeverity>;
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_DIAGNOSTIC_SEVERITY_H_
diff --git a/src/tint/ast/diagnostic_control_bench.cc b/src/tint/builtin/diagnostic_severity_bench.cc
similarity index 63%
rename from src/tint/ast/diagnostic_control_bench.cc
rename to src/tint/builtin/diagnostic_severity_bench.cc
index 6fb5014..13c3ff1 100644
--- a/src/tint/ast/diagnostic_control_bench.cc
+++ b/src/tint/builtin/diagnostic_severity_bench.cc
@@ -15,18 +15,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/diagnostic_control_bench.cc.tmpl
+//   src/tint/builtin/diagnostic_severity_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/diagnostic_control.h"
+#include "src/tint/builtin/diagnostic_severity.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 void DiagnosticSeverityParser(::benchmark::State& state) {
@@ -46,23 +46,5 @@
 
 BENCHMARK(DiagnosticSeverityParser);
 
-void DiagnosticRuleParser(::benchmark::State& state) {
-    const char* kStrings[] = {
-        "hromium_unyeachable_code",   "chrorrillmGunnreachable_c77de", "chromium_unreachable4cod00",
-        "chromium_unreachable_code",  "chromium_unracaboo_code",       "chromium_unrzzchabl_code",
-        "ciipp11ium_unreachable_cod", "derivXXtive_uniformity",        "55erivativeIIunifonn99ity",
-        "derirratHHaae_YniforSSity",  "derivative_uniformity",         "erivtive_unHkkormit",
-        "jerivaive_uniforRgty",       "derivatbve_unformiy",
-    };
-    for (auto _ : state) {
-        for (auto* str : kStrings) {
-            auto result = ParseDiagnosticRule(str);
-            benchmark::DoNotOptimize(result);
-        }
-    }
-}
-
-BENCHMARK(DiagnosticRuleParser);
-
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/diagnostic_control_bench.cc.tmpl b/src/tint/builtin/diagnostic_severity_bench.cc.tmpl
similarity index 79%
rename from src/tint/ast/diagnostic_control_bench.cc.tmpl
rename to src/tint/builtin/diagnostic_severity_bench.cc.tmpl
index 55d3cce..4d2dcee 100644
--- a/src/tint/ast/diagnostic_control_bench.cc.tmpl
+++ b/src/tint/builtin/diagnostic_severity_bench.cc.tmpl
@@ -10,18 +10,16 @@
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 
-#include "src/tint/ast/diagnostic_control.h"
+#include "src/tint/builtin/diagnostic_severity.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" (Sem.Enum "diagnostic_severity")}}
 
-{{ Eval "BenchmarkParseEnum" (Sem.Enum "diagnostic_rule")}}
-
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_severity_test.cc b/src/tint/builtin/diagnostic_severity_test.cc
new file mode 100644
index 0000000..bfd51b4
--- /dev/null
+++ b/src/tint/builtin/diagnostic_severity_test.cc
@@ -0,0 +1,89 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/diagnostic_severity_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include <string>
+
+#include "gtest/gtest-spi.h"
+#include "src/tint/builtin/diagnostic_severity.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace diagnostic_severity_tests {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    DiagnosticSeverity value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"error", DiagnosticSeverity::kError},
+    {"info", DiagnosticSeverity::kInfo},
+    {"off", DiagnosticSeverity::kOff},
+    {"warning", DiagnosticSeverity::kWarning},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"erccr", DiagnosticSeverity::kUndefined},    {"3o", DiagnosticSeverity::kUndefined},
+    {"eVror", DiagnosticSeverity::kUndefined},    {"1nfo", DiagnosticSeverity::kUndefined},
+    {"iqfJ", DiagnosticSeverity::kUndefined},     {"illf77", DiagnosticSeverity::kUndefined},
+    {"oppqH", DiagnosticSeverity::kUndefined},    {"", DiagnosticSeverity::kUndefined},
+    {"Gb", DiagnosticSeverity::kUndefined},       {"warniivg", DiagnosticSeverity::kUndefined},
+    {"8WWrning", DiagnosticSeverity::kUndefined}, {"wxxning", DiagnosticSeverity::kUndefined},
+};
+
+using DiagnosticSeverityParseTest = testing::TestWithParam<Case>;
+
+TEST_P(DiagnosticSeverityParseTest, Parse) {
+    const char* string = GetParam().string;
+    DiagnosticSeverity expect = GetParam().value;
+    EXPECT_EQ(expect, ParseDiagnosticSeverity(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticSeverityParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases,
+                         DiagnosticSeverityParseTest,
+                         testing::ValuesIn(kInvalidCases));
+
+using DiagnosticSeverityPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(DiagnosticSeverityPrintTest, Print) {
+    DiagnosticSeverity value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticSeverityPrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace diagnostic_severity_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_severity_test.cc.tmpl b/src/tint/builtin/diagnostic_severity_test.cc.tmpl
new file mode 100644
index 0000000..1bd06b4
--- /dev/null
+++ b/src/tint/builtin/diagnostic_severity_test.cc.tmpl
@@ -0,0 +1,29 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate diagnostic_control_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include <string>
+
+#include "gtest/gtest-spi.h"
+#include "src/tint/builtin/diagnostic_severity.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace diagnostic_severity_tests {
+
+{{ Eval "TestParsePrintEnum" (Sem.Enum "diagnostic_severity")}}
+
+}  // namespace diagnostic_severity_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling.cc b/src/tint/builtin/interpolation_sampling.cc
new file mode 100644
index 0000000..8b39930
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling.cc
@@ -0,0 +1,60 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_sampling.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/interpolation_sampling.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+/// ParseInterpolationSampling parses a InterpolationSampling from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or InterpolationSampling::kUndefined if the string could not be
+/// parsed.
+InterpolationSampling ParseInterpolationSampling(std::string_view str) {
+    if (str == "center") {
+        return InterpolationSampling::kCenter;
+    }
+    if (str == "centroid") {
+        return InterpolationSampling::kCentroid;
+    }
+    if (str == "sample") {
+        return InterpolationSampling::kSample;
+    }
+    return InterpolationSampling::kUndefined;
+}
+
+std::ostream& operator<<(std::ostream& out, InterpolationSampling value) {
+    switch (value) {
+        case InterpolationSampling::kUndefined:
+            return out << "undefined";
+        case InterpolationSampling::kCenter:
+            return out << "center";
+        case InterpolationSampling::kCentroid:
+            return out << "centroid";
+        case InterpolationSampling::kSample:
+            return out << "sample";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling.cc.tmpl b/src/tint/builtin/interpolation_sampling.cc.tmpl
new file mode 100644
index 0000000..1063ded
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling.cc.tmpl
@@ -0,0 +1,23 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/interpolation_sampling.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+{{ Eval "ParseEnum" (Sem.Enum "interpolation_sampling")}}
+
+{{ Eval "EnumOStream" (Sem.Enum "interpolation_sampling")}}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling.h b/src/tint/builtin/interpolation_sampling.h
new file mode 100644
index 0000000..a3fc357
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling.h
@@ -0,0 +1,58 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_sampling.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// The interpolation sampling.
+enum class InterpolationSampling {
+    kUndefined,
+    kCenter,
+    kCentroid,
+    kSample,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the InterpolationSampling
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, InterpolationSampling value);
+
+/// ParseInterpolationSampling parses a InterpolationSampling from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or InterpolationSampling::kUndefined if the string could not be
+/// parsed.
+InterpolationSampling ParseInterpolationSampling(std::string_view str);
+
+constexpr const char* kInterpolationSamplingStrings[] = {
+    "center",
+    "centroid",
+    "sample",
+};
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
diff --git a/src/tint/builtin/interpolation_sampling.h.tmpl b/src/tint/builtin/interpolation_sampling.h.tmpl
new file mode 100644
index 0000000..24b3b02
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling.h.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate interpolate_attribute.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#ifndef SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// The interpolation sampling.
+{{ Eval "DeclareEnum" (Sem.Enum "interpolation_sampling") }}
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
diff --git a/src/tint/type/access_bench.cc b/src/tint/builtin/interpolation_sampling_bench.cc
similarity index 62%
copy from src/tint/type/access_bench.cc
copy to src/tint/builtin/interpolation_sampling_bench.cc
index ab578eb..4fb7e09 100644
--- a/src/tint/type/access_bench.cc
+++ b/src/tint/builtin/interpolation_sampling_bench.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Tint Authors.
+// Copyright 2023 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.
@@ -15,37 +15,34 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/access_bench.cc.tmpl
+//   src/tint/builtin/interpolation_sampling_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/access.h"
-
 #include <array>
 
 #include "benchmark/benchmark.h"
+#include "src/tint/builtin/interpolation_sampling.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
-void AccessParser(::benchmark::State& state) {
+void InterpolationSamplingParser(::benchmark::State& state) {
     const char* kStrings[] = {
-        "ccad",       "3",           "rVad",         "read",       "1ead",
-        "rqaJ",       "rlla77",      "reqqdppriHHe", "rv_wcit",    "reabGwrte",
-        "read_write", "read_vriite", "re8d_wriWWe",  "Meadxxrite", "wggte",
-        "VtX",        "writ3",       "write",        "writE",      "TTrPte",
-        "wxxidd",
+        "ccnter",     "c3r",   "centeV",  "center",   "1enter",    "cnqqer",    "centll77",
+        "qqenrppHid", "cntov", "cenGoid", "centroid", "ceviiroid", "ceWWtro8d", "cxxtMoid",
+        "saXggl",     "Xmle",  "sam3le",  "sample",   "sEmple",    "amTTlPP",   "ddamxxl",
     };
     for (auto _ : state) {
         for (auto* str : kStrings) {
-            auto result = ParseAccess(str);
+            auto result = ParseInterpolationSampling(str);
             benchmark::DoNotOptimize(result);
         }
     }
 }
 
-BENCHMARK(AccessParser);
+BENCHMARK(InterpolationSamplingParser);
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/ast/interpolate_attribute_bench.cc.tmpl b/src/tint/builtin/interpolation_sampling_bench.cc.tmpl
similarity index 78%
copy from src/tint/ast/interpolate_attribute_bench.cc.tmpl
copy to src/tint/builtin/interpolation_sampling_bench.cc.tmpl
index b75fe44..b2b29f4 100644
--- a/src/tint/ast/interpolate_attribute_bench.cc.tmpl
+++ b/src/tint/builtin/interpolation_sampling_bench.cc.tmpl
@@ -10,18 +10,15 @@
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 
-#include "src/tint/ast/interpolate_attribute.h"
-
 #include <array>
 
 #include "benchmark/benchmark.h"
+#include "src/tint/builtin/interpolation_sampling.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
-{{ Eval "BenchmarkParseEnum" (Sem.Enum "interpolation_type")}}
-
 {{ Eval "BenchmarkParseEnum" (Sem.Enum "interpolation_sampling")}}
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling_test.cc b/src/tint/builtin/interpolation_sampling_test.cc
new file mode 100644
index 0000000..db497a8
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling_test.cc
@@ -0,0 +1,96 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_sampling_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/interpolation_sampling.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace interpolation_sampling_tests {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    InterpolationSampling value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"center", InterpolationSampling::kCenter},
+    {"centroid", InterpolationSampling::kCentroid},
+    {"sample", InterpolationSampling::kSample},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"ccnter", InterpolationSampling::kUndefined},
+    {"c3r", InterpolationSampling::kUndefined},
+    {"centeV", InterpolationSampling::kUndefined},
+    {"1entroid", InterpolationSampling::kUndefined},
+    {"enJrqqid", InterpolationSampling::kUndefined},
+    {"llen77roid", InterpolationSampling::kUndefined},
+    {"sapppHHe", InterpolationSampling::kUndefined},
+    {"cam", InterpolationSampling::kUndefined},
+    {"sbGpl", InterpolationSampling::kUndefined},
+};
+
+using InterpolationSamplingParseTest = testing::TestWithParam<Case>;
+
+TEST_P(InterpolationSamplingParseTest, Parse) {
+    const char* string = GetParam().string;
+    InterpolationSampling expect = GetParam().value;
+    EXPECT_EQ(expect, ParseInterpolationSampling(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases,
+                         InterpolationSamplingParseTest,
+                         testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases,
+                         InterpolationSamplingParseTest,
+                         testing::ValuesIn(kInvalidCases));
+
+using InterpolationSamplingPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(InterpolationSamplingPrintTest, Print) {
+    InterpolationSampling value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases,
+                         InterpolationSamplingPrintTest,
+                         testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace interpolation_sampling_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling_test.cc.tmpl b/src/tint/builtin/interpolation_sampling_test.cc.tmpl
new file mode 100644
index 0000000..ed77d63
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling_test.cc.tmpl
@@ -0,0 +1,30 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate interpolate_attribute_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/interpolation_sampling.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace interpolation_sampling_tests {
+
+{{ Eval "TestParsePrintEnum" (Sem.Enum "interpolation_sampling")}}
+
+}  // namespace interpolation_sampling_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type.cc b/src/tint/builtin/interpolation_type.cc
new file mode 100644
index 0000000..ee3f68b
--- /dev/null
+++ b/src/tint/builtin/interpolation_type.cc
@@ -0,0 +1,59 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_type.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/interpolation_type.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+/// ParseInterpolationType parses a InterpolationType from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or InterpolationType::kUndefined if the string could not be parsed.
+InterpolationType ParseInterpolationType(std::string_view str) {
+    if (str == "flat") {
+        return InterpolationType::kFlat;
+    }
+    if (str == "linear") {
+        return InterpolationType::kLinear;
+    }
+    if (str == "perspective") {
+        return InterpolationType::kPerspective;
+    }
+    return InterpolationType::kUndefined;
+}
+
+std::ostream& operator<<(std::ostream& out, InterpolationType value) {
+    switch (value) {
+        case InterpolationType::kUndefined:
+            return out << "undefined";
+        case InterpolationType::kFlat:
+            return out << "flat";
+        case InterpolationType::kLinear:
+            return out << "linear";
+        case InterpolationType::kPerspective:
+            return out << "perspective";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type.cc.tmpl b/src/tint/builtin/interpolation_type.cc.tmpl
new file mode 100644
index 0000000..4158a29
--- /dev/null
+++ b/src/tint/builtin/interpolation_type.cc.tmpl
@@ -0,0 +1,23 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/interpolation_type.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+{{ Eval "ParseEnum" (Sem.Enum "interpolation_type")}}
+
+{{ Eval "EnumOStream" (Sem.Enum "interpolation_type")}}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type.h b/src/tint/builtin/interpolation_type.h
new file mode 100644
index 0000000..ee54964
--- /dev/null
+++ b/src/tint/builtin/interpolation_type.h
@@ -0,0 +1,57 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_type.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// The interpolation type.
+enum class InterpolationType {
+    kUndefined,
+    kFlat,
+    kLinear,
+    kPerspective,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the InterpolationType
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, InterpolationType value);
+
+/// ParseInterpolationType parses a InterpolationType from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or InterpolationType::kUndefined if the string could not be parsed.
+InterpolationType ParseInterpolationType(std::string_view str);
+
+constexpr const char* kInterpolationTypeStrings[] = {
+    "flat",
+    "linear",
+    "perspective",
+};
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
diff --git a/src/tint/builtin/interpolation_type.h.tmpl b/src/tint/builtin/interpolation_type.h.tmpl
new file mode 100644
index 0000000..c869a96
--- /dev/null
+++ b/src/tint/builtin/interpolation_type.h.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate interpolate_attribute.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#ifndef SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// The interpolation type.
+{{ Eval "DeclareEnum" (Sem.Enum "interpolation_type") }}
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
diff --git a/src/tint/ast/interpolate_attribute_bench.cc b/src/tint/builtin/interpolation_type_bench.cc
similarity index 66%
rename from src/tint/ast/interpolate_attribute_bench.cc
rename to src/tint/builtin/interpolation_type_bench.cc
index 722cb06..5098f26 100644
--- a/src/tint/ast/interpolate_attribute_bench.cc
+++ b/src/tint/builtin/interpolation_type_bench.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Tint Authors.
+// Copyright 2023 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.
@@ -15,18 +15,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/interpolate_attribute_bench.cc.tmpl
+//   src/tint/builtin/interpolation_type_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/interpolate_attribute.h"
+#include "src/tint/builtin/interpolation_type.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 void InterpolationTypeParser(::benchmark::State& state) {
@@ -47,21 +47,5 @@
 
 BENCHMARK(InterpolationTypeParser);
 
-void InterpolationSamplingParser(::benchmark::State& state) {
-    const char* kStrings[] = {
-        "44enter", "cSSVVter",     "centRr",     "center",   "ent9r",  "cente",   "VentORr",
-        "cenyroi", "77errtrllnid", "04entroid",  "centroid", "enooid", "centzzd", "ceiippr1i",
-        "saXXple", "55IImpnn99",   "aHHrrmplSS", "sample",   "kkle",   "jagRR",   "smbe",
-    };
-    for (auto _ : state) {
-        for (auto* str : kStrings) {
-            auto result = ParseInterpolationSampling(str);
-            benchmark::DoNotOptimize(result);
-        }
-    }
-}
-
-BENCHMARK(InterpolationSamplingParser);
-
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/interpolate_attribute_bench.cc.tmpl b/src/tint/builtin/interpolation_type_bench.cc.tmpl
similarity index 78%
rename from src/tint/ast/interpolate_attribute_bench.cc.tmpl
rename to src/tint/builtin/interpolation_type_bench.cc.tmpl
index b75fe44..1b5df2e 100644
--- a/src/tint/ast/interpolate_attribute_bench.cc.tmpl
+++ b/src/tint/builtin/interpolation_type_bench.cc.tmpl
@@ -10,18 +10,16 @@
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 
-#include "src/tint/ast/interpolate_attribute.h"
+#include "src/tint/builtin/interpolation_type.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" (Sem.Enum "interpolation_type")}}
 
-{{ Eval "BenchmarkParseEnum" (Sem.Enum "interpolation_sampling")}}
-
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type_test.cc b/src/tint/builtin/interpolation_type_test.cc
new file mode 100644
index 0000000..96e7094
--- /dev/null
+++ b/src/tint/builtin/interpolation_type_test.cc
@@ -0,0 +1,88 @@
+// Copyright 2023 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_type_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/interpolation_type.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace interpolation_type_tests {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    InterpolationType value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"flat", InterpolationType::kFlat},
+    {"linear", InterpolationType::kLinear},
+    {"perspective", InterpolationType::kPerspective},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"ccat", InterpolationType::kUndefined},          {"3", InterpolationType::kUndefined},
+    {"fVat", InterpolationType::kUndefined},          {"1inear", InterpolationType::kUndefined},
+    {"lnqqar", InterpolationType::kUndefined},        {"linell77", InterpolationType::kUndefined},
+    {"perppHqective", InterpolationType::kUndefined}, {"cespctve", InterpolationType::kUndefined},
+    {"ebGpective", InterpolationType::kUndefined},
+};
+
+using InterpolationTypeParseTest = testing::TestWithParam<Case>;
+
+TEST_P(InterpolationTypeParseTest, Parse) {
+    const char* string = GetParam().string;
+    InterpolationType expect = GetParam().value;
+    EXPECT_EQ(expect, ParseInterpolationType(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypeParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases,
+                         InterpolationTypeParseTest,
+                         testing::ValuesIn(kInvalidCases));
+
+using InterpolationTypePrintTest = testing::TestWithParam<Case>;
+
+TEST_P(InterpolationTypePrintTest, Print) {
+    InterpolationType value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypePrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace interpolation_type_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type_test.cc.tmpl b/src/tint/builtin/interpolation_type_test.cc.tmpl
new file mode 100644
index 0000000..a1a48b9
--- /dev/null
+++ b/src/tint/builtin/interpolation_type_test.cc.tmpl
@@ -0,0 +1,30 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate interpolate_attribute_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/interpolation_type.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace interpolation_type_tests {
+
+{{ Eval "TestParsePrintEnum" (Sem.Enum "interpolation_type")}}
+
+}  // namespace interpolation_type_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/type/texel_format.cc b/src/tint/builtin/texel_format.cc
similarity index 96%
rename from src/tint/type/texel_format.cc
rename to src/tint/builtin/texel_format.cc
index ebf2fc0..dc4bbfe 100644
--- a/src/tint/type/texel_format.cc
+++ b/src/tint/builtin/texel_format.cc
@@ -15,14 +15,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/texel_format.cc.tmpl
+//   src/tint/builtin/texel_format.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/texel_format.h"
+#include "src/tint/builtin/texel_format.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// ParseTexelFormat parses a TexelFormat from a string.
 /// @param str the string to parse
@@ -124,4 +124,4 @@
     return out << "<unknown>";
 }
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/texel_format.cc.tmpl b/src/tint/builtin/texel_format.cc.tmpl
similarity index 84%
rename from src/tint/type/texel_format.cc.tmpl
rename to src/tint/builtin/texel_format.cc.tmpl
index 716ff69..d67fc90 100644
--- a/src/tint/type/texel_format.cc.tmpl
+++ b/src/tint/builtin/texel_format.cc.tmpl
@@ -11,12 +11,12 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "texel_format") -}}
 
-#include "src/tint/type/texel_format.h"
+#include "src/tint/builtin/texel_format.h"
 
-namespace tint::type {
+namespace tint::builtin {
 
 {{ Eval "ParseEnum" $enum}}
 
 {{ Eval "EnumOStream" $enum}}
 
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/texel_format.h b/src/tint/builtin/texel_format.h
similarity index 89%
rename from src/tint/type/texel_format.h
rename to src/tint/builtin/texel_format.h
index a4c8e92..9611e62 100644
--- a/src/tint/type/texel_format.h
+++ b/src/tint/builtin/texel_format.h
@@ -15,17 +15,17 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/texel_format.h.tmpl
+//   src/tint/builtin/texel_format.h.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#ifndef SRC_TINT_TYPE_TEXEL_FORMAT_H_
-#define SRC_TINT_TYPE_TEXEL_FORMAT_H_
+#ifndef SRC_TINT_BUILTIN_TEXEL_FORMAT_H_
+#define SRC_TINT_BUILTIN_TEXEL_FORMAT_H_
 
 #include <ostream>
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// Enumerator of texel formats
 enum class TexelFormat {
@@ -65,6 +65,6 @@
     "rgba32uint", "rgba8sint",   "rgba8snorm", "rgba8uint",  "rgba8unorm",
 };
 
-}  // namespace tint::type
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_TYPE_TEXEL_FORMAT_H_
+#endif  // SRC_TINT_BUILTIN_TEXEL_FORMAT_H_
diff --git a/src/tint/type/texel_format.h.tmpl b/src/tint/builtin/texel_format.h.tmpl
similarity index 75%
rename from src/tint/type/texel_format.h.tmpl
rename to src/tint/builtin/texel_format.h.tmpl
index 837c226..a3a9e31 100644
--- a/src/tint/type/texel_format.h.tmpl
+++ b/src/tint/builtin/texel_format.h.tmpl
@@ -11,16 +11,16 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "texel_format") -}}
 
-#ifndef SRC_TINT_TYPE_TEXEL_FORMAT_H_
-#define SRC_TINT_TYPE_TEXEL_FORMAT_H_
+#ifndef SRC_TINT_BUILTIN_TEXEL_FORMAT_H_
+#define SRC_TINT_BUILTIN_TEXEL_FORMAT_H_
 
 #include <ostream>
 
-namespace tint::type {
+namespace tint::builtin {
 
 /// Enumerator of texel formats
 {{ Eval "DeclareEnum" $enum}}
 
-}  // namespace tint::type
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_TYPE_TEXEL_FORMAT_H_
+#endif  // SRC_TINT_BUILTIN_TEXEL_FORMAT_H_
diff --git a/src/tint/type/texel_format_bench.cc b/src/tint/builtin/texel_format_bench.cc
similarity index 95%
rename from src/tint/type/texel_format_bench.cc
rename to src/tint/builtin/texel_format_bench.cc
index 6a0ea27..5d202ea 100644
--- a/src/tint/type/texel_format_bench.cc
+++ b/src/tint/builtin/texel_format_bench.cc
@@ -15,18 +15,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/texel_format_bench.cc.tmpl
+//   src/tint/builtin/texel_format_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/texel_format.h"
+#include "src/tint/builtin/texel_format.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 void TexelFormatParser(::benchmark::State& state) {
@@ -67,4 +67,4 @@
 BENCHMARK(TexelFormatParser);
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/texel_format_bench.cc.tmpl b/src/tint/builtin/texel_format_bench.cc.tmpl
similarity index 85%
rename from src/tint/type/texel_format_bench.cc.tmpl
rename to src/tint/builtin/texel_format_bench.cc.tmpl
index 2561dac..ac7249a 100644
--- a/src/tint/type/texel_format_bench.cc.tmpl
+++ b/src/tint/builtin/texel_format_bench.cc.tmpl
@@ -11,16 +11,16 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "texel_format") -}}
 
-#include "src/tint/type/texel_format.h"
+#include "src/tint/builtin/texel_format.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" $enum }}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/texel_format_test.cc b/src/tint/builtin/texel_format_test.cc
similarity index 96%
rename from src/tint/type/texel_format_test.cc
rename to src/tint/builtin/texel_format_test.cc
index c7bc0e4..453224c 100644
--- a/src/tint/type/texel_format_test.cc
+++ b/src/tint/builtin/texel_format_test.cc
@@ -15,19 +15,20 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/type/texel_format_test.cc.tmpl
+//   src/tint/builtin/texel_format_test.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/type/texel_format.h"
+#include "src/tint/builtin/texel_format.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/type/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 namespace parse_print_tests {
@@ -106,4 +107,4 @@
 }  // namespace parse_print_tests
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/type/texel_format_test.cc.tmpl b/src/tint/builtin/texel_format_test.cc.tmpl
similarity index 82%
rename from src/tint/type/texel_format_test.cc.tmpl
rename to src/tint/builtin/texel_format_test.cc.tmpl
index e7a0e59..8babb9b 100644
--- a/src/tint/type/texel_format_test.cc.tmpl
+++ b/src/tint/builtin/texel_format_test.cc.tmpl
@@ -11,17 +11,18 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "texel_format") -}}
 
-#include "src/tint/type/texel_format.h"
+#include "src/tint/builtin/texel_format.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/type/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::type {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "TestParsePrintEnum" $enum}}
 
 }  // namespace
-}  // namespace tint::type
+}  // namespace tint::builtin
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
index a2ab29c..dfe1a83 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
@@ -214,7 +214,7 @@
 TEST(DeleteStatementTest, DeleteCall) {
     auto original = R"(
 fn main() {
-  sin(1.0);
+  workgroupBarrier();
 })";
     auto expected = R"(
 fn main() {
diff --git a/src/tint/fuzzers/transform_builder.h b/src/tint/fuzzers/transform_builder.h
index 90d6af5..73b5b51 100644
--- a/src/tint/fuzzers/transform_builder.h
+++ b/src/tint/fuzzers/transform_builder.h
@@ -131,7 +131,7 @@
                 uint8_t old_binding;
                 uint8_t new_group;
                 uint8_t new_binding;
-                type::Access new_access;
+                builtin::Access new_access;
             };
 
             std::vector<Config> configs = tb->builder()->vector<Config>();
diff --git a/src/tint/inspector/entry_point.cc b/src/tint/inspector/entry_point.cc
index a6c3b8c..cf39df2 100644
--- a/src/tint/inspector/entry_point.cc
+++ b/src/tint/inspector/entry_point.cc
@@ -21,8 +21,6 @@
     : name(other.name),
       has_location_attribute(other.has_location_attribute),
       location_attribute(other.location_attribute),
-      has_location_decoration(has_location_attribute),
-      location_decoration(location_attribute),
       component_type(other.component_type),
       composition_type(other.composition_type),
       interpolation_type(other.interpolation_type),
diff --git a/src/tint/inspector/entry_point.h b/src/tint/inspector/entry_point.h
index eabe601..fd17ba0 100644
--- a/src/tint/inspector/entry_point.h
+++ b/src/tint/inspector/entry_point.h
@@ -68,13 +68,6 @@
     /// Value of the location attribute, only valid if #has_location_attribute is
     /// true.
     uint32_t location_attribute;
-    /// Is Location attribute present
-    /// [DEPRECATED]: Use #has_location_attribute
-    bool& has_location_decoration = has_location_attribute;
-    /// Value of Location Decoration, only valid if #has_location_decoration is
-    /// true.
-    /// [DEPRECATED]: Use #location_attribute
-    uint32_t& location_decoration = location_attribute;
     /// Scalar type that the variable is composed of.
     ComponentType component_type = ComponentType::kUnknown;
     /// How the scalars are composed for the variable.
diff --git a/src/tint/inspector/inspector.cc b/src/tint/inspector/inspector.cc
index 40658db..6e96523 100644
--- a/src/tint/inspector/inspector.cc
+++ b/src/tint/inspector/inspector.cc
@@ -28,7 +28,11 @@
 #include "src/tint/ast/module.h"
 #include "src/tint/ast/override.h"
 #include "src/tint/ast/var.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/builtin/extension.h"
+#include "src/tint/builtin/interpolation_sampling.h"
+#include "src/tint/builtin/interpolation_type.h"
+#include "src/tint/sem/builtin_enum_expression.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/module.h"
@@ -115,59 +119,6 @@
     return {componentType, compositionType};
 }
 
-std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData(
-    const type::Type* type,
-    utils::VectorRef<const ast::Attribute*> attributes) {
-    auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes);
-    if (type->is_integer_scalar_or_vector()) {
-        return {InterpolationType::kFlat, InterpolationSampling::kNone};
-    }
-
-    if (!interpolation_attribute) {
-        return {InterpolationType::kPerspective, InterpolationSampling::kCenter};
-    }
-
-    auto ast_interpolation_type = interpolation_attribute->type;
-    auto ast_sampling_type = interpolation_attribute->sampling;
-    if (ast_interpolation_type != ast::InterpolationType::kFlat &&
-        ast_sampling_type == ast::InterpolationSampling::kUndefined) {
-        ast_sampling_type = ast::InterpolationSampling::kCenter;
-    }
-
-    auto interpolation_type = InterpolationType::kUnknown;
-    switch (ast_interpolation_type) {
-        case ast::InterpolationType::kPerspective:
-            interpolation_type = InterpolationType::kPerspective;
-            break;
-        case ast::InterpolationType::kLinear:
-            interpolation_type = InterpolationType::kLinear;
-            break;
-        case ast::InterpolationType::kFlat:
-            interpolation_type = InterpolationType::kFlat;
-            break;
-        case ast::InterpolationType::kUndefined:
-            break;
-    }
-
-    auto sampling_type = InterpolationSampling::kUnknown;
-    switch (ast_sampling_type) {
-        case ast::InterpolationSampling::kUndefined:
-            sampling_type = InterpolationSampling::kNone;
-            break;
-        case ast::InterpolationSampling::kCenter:
-            sampling_type = InterpolationSampling::kCenter;
-            break;
-        case ast::InterpolationSampling::kCentroid:
-            sampling_type = InterpolationSampling::kCentroid;
-            break;
-        case ast::InterpolationSampling::kSample:
-            sampling_type = InterpolationSampling::kSample;
-            break;
-    }
-
-    return {interpolation_type, sampling_type};
-}
-
 }  // namespace
 
 Inspector::Inspector(const Program* program) : program_(program) {}
@@ -541,7 +492,7 @@
                                       ResourceBinding::ResourceType::kExternalTexture);
 }
 
-utils::VectorRef<sem::SamplerTexturePair> Inspector::GetSamplerTextureUses(
+utils::VectorRef<SamplerTexturePair> Inspector::GetSamplerTextureUses(
     const std::string& entry_point) {
     auto* func = FindEntryPointByName(entry_point);
     if (!func) {
@@ -557,7 +508,7 @@
     return it->second;
 }
 
-std::vector<sem::SamplerTexturePair> Inspector::GetSamplerTextureUses(
+std::vector<SamplerTexturePair> Inspector::GetSamplerTextureUses(
     const std::string& entry_point,
     const sem::BindingPoint& placeholder) {
     auto* func = FindEntryPointByName(entry_point);
@@ -566,7 +517,7 @@
     }
     auto* func_sem = program_->Sem().Get(func);
 
-    std::vector<sem::SamplerTexturePair> new_pairs;
+    std::vector<SamplerTexturePair> new_pairs;
     for (auto pair : func_sem->TextureSamplerPairs()) {
         auto* texture = pair.first->As<sem::GlobalVariable>();
         auto* sampler = pair.second ? pair.second->As<sem::GlobalVariable>() : nullptr;
@@ -587,7 +538,7 @@
     uint32_t total_size = 0;
     auto* func_sem = program_->Sem().Get(func);
     for (const sem::Variable* var : func_sem->TransitivelyReferencedGlobals()) {
-        if (var->AddressSpace() == type::AddressSpace::kWorkgroup) {
+        if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
             auto* ty = var->Type()->UnwrapRef();
             uint32_t align = ty->Align();
             uint32_t size = ty->Size();
@@ -698,11 +649,10 @@
 
     // Base case: check for builtin
     auto* builtin_declaration = ast::GetAttribute<ast::BuiltinAttribute>(attributes);
-    if (!builtin_declaration || builtin_declaration->builtin != builtin) {
+    if (!builtin_declaration) {
         return false;
     }
-
-    return true;
+    return program_->Sem().Get(builtin_declaration)->Value() == builtin;
 }
 
 std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
@@ -719,7 +669,7 @@
         auto* var = rsv.first;
         auto binding_info = rsv.second;
 
-        if (read_only != (var->Access() == type::Access::kRead)) {
+        if (read_only != (var->Access() == builtin::Access::kRead)) {
             continue;
         }
 
@@ -825,7 +775,7 @@
     }
 
     sampler_targets_ = std::make_unique<
-        std::unordered_map<std::string, utils::UniqueVector<sem::SamplerTexturePair, 4>>>();
+        std::unordered_map<std::string, utils::UniqueVector<SamplerTexturePair, 4>>>();
 
     auto& sem = program_->Sem();
 
@@ -886,6 +836,70 @@
     }
 }
 
+std::tuple<InterpolationType, InterpolationSampling> Inspector::CalculateInterpolationData(
+    const type::Type* type,
+    utils::VectorRef<const ast::Attribute*> attributes) const {
+    auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes);
+    if (type->is_integer_scalar_or_vector()) {
+        return {InterpolationType::kFlat, InterpolationSampling::kNone};
+    }
+
+    if (!interpolation_attribute) {
+        return {InterpolationType::kPerspective, InterpolationSampling::kCenter};
+    }
+
+    auto& sem = program_->Sem();
+
+    auto ast_interpolation_type = sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(
+                                         interpolation_attribute->type)
+                                      ->Value();
+
+    auto ast_sampling_type = builtin::InterpolationSampling::kUndefined;
+    if (interpolation_attribute->sampling) {
+        ast_sampling_type = sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
+                                   interpolation_attribute->sampling)
+                                ->Value();
+    }
+
+    if (ast_interpolation_type != builtin::InterpolationType::kFlat &&
+        ast_sampling_type == builtin::InterpolationSampling::kUndefined) {
+        ast_sampling_type = builtin::InterpolationSampling::kCenter;
+    }
+
+    auto interpolation_type = InterpolationType::kUnknown;
+    switch (ast_interpolation_type) {
+        case builtin::InterpolationType::kPerspective:
+            interpolation_type = InterpolationType::kPerspective;
+            break;
+        case builtin::InterpolationType::kLinear:
+            interpolation_type = InterpolationType::kLinear;
+            break;
+        case builtin::InterpolationType::kFlat:
+            interpolation_type = InterpolationType::kFlat;
+            break;
+        case builtin::InterpolationType::kUndefined:
+            break;
+    }
+
+    auto sampling_type = InterpolationSampling::kUnknown;
+    switch (ast_sampling_type) {
+        case builtin::InterpolationSampling::kUndefined:
+            sampling_type = InterpolationSampling::kNone;
+            break;
+        case builtin::InterpolationSampling::kCenter:
+            sampling_type = InterpolationSampling::kCenter;
+            break;
+        case builtin::InterpolationSampling::kCentroid:
+            sampling_type = InterpolationSampling::kCentroid;
+            break;
+        case builtin::InterpolationSampling::kSample:
+            sampling_type = InterpolationSampling::kSample;
+            break;
+    }
+
+    return {interpolation_type, sampling_type};
+}
+
 template <size_t N, typename F>
 void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& callback) {
     if (TINT_UNLIKELY(!program_->IsValid())) {
diff --git a/src/tint/inspector/inspector.h b/src/tint/inspector/inspector.h
index 5854125..443bbab 100644
--- a/src/tint/inspector/inspector.h
+++ b/src/tint/inspector/inspector.h
@@ -25,6 +25,7 @@
 
 #include "tint/override_id.h"
 
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/inspector/entry_point.h"
 #include "src/tint/inspector/resource_binding.h"
 #include "src/tint/inspector/scalar.h"
@@ -126,16 +127,15 @@
     /// @param entry_point name of the entry point to get information about.
     /// @returns vector of all of the sampler/texture sampling pairs that are used
     /// by that entry point.
-    utils::VectorRef<sem::SamplerTexturePair> GetSamplerTextureUses(const std::string& entry_point);
+    utils::VectorRef<SamplerTexturePair> GetSamplerTextureUses(const std::string& entry_point);
 
     /// @param entry_point name of the entry point to get information about.
     /// @param placeholder the sampler binding point to use for texture-only
     /// access (e.g., textureLoad)
     /// @returns vector of all of the sampler/texture sampling pairs that are used
     /// by that entry point.
-    std::vector<sem::SamplerTexturePair> GetSamplerTextureUses(
-        const std::string& entry_point,
-        const sem::BindingPoint& placeholder);
+    std::vector<SamplerTexturePair> GetSamplerTextureUses(const std::string& entry_point,
+                                                          const sem::BindingPoint& placeholder);
 
     /// @param entry_point name of the entry point to get information about.
     /// @returns the total size in bytes of all Workgroup storage-class storage
@@ -157,8 +157,7 @@
   private:
     const Program* program_;
     diag::List diagnostics_;
-    std::unique_ptr<
-        std::unordered_map<std::string, utils::UniqueVector<sem::SamplerTexturePair, 4>>>
+    std::unique_ptr<std::unordered_map<std::string, utils::UniqueVector<SamplerTexturePair, 4>>>
         sampler_targets_;
 
     /// @param name name of the entry point to find
@@ -223,6 +222,13 @@
     /// Constructs |sampler_targets_| if it hasn't already been instantiated.
     void GenerateSamplerTargets();
 
+    /// @param type the type of the parameter or structure member
+    /// @param attributes attributes associated with the parameter or structure member
+    /// @returns the interpolation type and sampling modes for the value
+    std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData(
+        const type::Type* type,
+        utils::VectorRef<const ast::Attribute*> attributes) const;
+
     /// For a N-uple of expressions, resolve to the appropriate global resources
     /// and call 'cb'.
     /// 'cb' may be called multiple times.
diff --git a/src/tint/inspector/inspector_test.cc b/src/tint/inspector/inspector_test.cc
index 743f878..b359074 100644
--- a/src/tint/inspector/inspector_test.cc
+++ b/src/tint/inspector/inspector_test.cc
@@ -51,8 +51,8 @@
     : public InspectorBuilder,
       public testing::TestWithParam<InspectorGetEntryPointComponentAndCompositionTestParams> {};
 struct InspectorGetEntryPointInterpolateTestParams {
-    ast::InterpolationType in_type;
-    ast::InterpolationSampling in_sampling;
+    builtin::InterpolationType in_type;
+    builtin::InterpolationSampling in_sampling;
     inspector::InterpolationType out_type;
     inspector::InterpolationSampling out_sampling;
 };
@@ -112,7 +112,7 @@
                                                                  public testing::Test {};
 
 typedef std::tuple<type::TextureDimension, ResourceBinding::TextureDimension> DimensionParams;
-typedef std::tuple<type::TexelFormat, ResourceBinding::TexelFormat, ResourceBinding::SampledKind>
+typedef std::tuple<builtin::TexelFormat, ResourceBinding::TexelFormat, ResourceBinding::SampledKind>
     TexelFormatParams;
 typedef std::tuple<DimensionParams, TexelFormatParams> GetStorageTextureTestParams;
 class InspectorGetStorageTextureResourceBindingsTestWithParam
@@ -743,7 +743,7 @@
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedIndirectly_ViaPrivateInitializer) {
     Override("foo", ty.f32());
-    GlobalVar("bar", type::AddressSpace::kPrivate, ty.f32(), Mul(2_a, "foo"));
+    GlobalVar("bar", builtin::AddressSpace::kPrivate, ty.f32(), Mul(2_a, "foo"));
     MakePlainGlobalReferenceBodyFunction("ep_func", "bar", ty.f32(),
                                          utils::Vector{
                                              Stage(ast::PipelineStage::kCompute),
@@ -834,7 +834,7 @@
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByArraySize) {
     Override("size", ty.u32());
-    GlobalVar("v", type::AddressSpace::kWorkgroup, ty.array(ty.f32(), "size"));
+    GlobalVar("v", builtin::AddressSpace::kWorkgroup, ty.array(ty.f32(), "size"));
     Func("ep", utils::Empty, ty.void_(),
          utils::Vector{
              Assign(Phony(), IndexAccessor("v", 0_a)),
@@ -857,7 +857,7 @@
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByArraySizeIndirectly) {
     Override("foo", ty.u32());
     Override("bar", ty.u32(), Mul(2_a, "foo"));
-    GlobalVar("v", type::AddressSpace::kWorkgroup, ty.array(ty.f32(), Mul(2_a, Expr("bar"))));
+    GlobalVar("v", builtin::AddressSpace::kWorkgroup, ty.array(ty.f32(), Mul(2_a, Expr("bar"))));
     Func("ep", utils::Empty, ty.void_(),
          utils::Vector{
              Assign(Phony(), IndexAccessor("v", 0_a)),
@@ -885,7 +885,7 @@
     Alias("MyArray", ty.array(ty.f32(), Mul(2_a, Expr("bar"))));
     Override("zoo", ty.u32());
     Alias("MyArrayUnused", ty.array(ty.f32(), Mul(2_a, Expr("zoo"))));
-    GlobalVar("v", type::AddressSpace::kWorkgroup, ty("MyArray"));
+    GlobalVar("v", builtin::AddressSpace::kWorkgroup, ty("MyArray"));
     Func("ep", utils::Empty, ty.void_(),
          utils::Vector{
              Assign(Phony(), IndexAccessor("v", 0_a)),
@@ -1436,31 +1436,31 @@
     InspectorGetEntryPointInterpolateTest,
     testing::Values(
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCenter,
+            builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kCenter,
             InterpolationType::kPerspective, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCentroid,
+            builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kCentroid,
             InterpolationType::kPerspective, InterpolationSampling::kCentroid},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kSample,
+            builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kSample,
             InterpolationType::kPerspective, InterpolationSampling::kSample},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kUndefined,
+            builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kUndefined,
             InterpolationType::kPerspective, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear, ast::InterpolationSampling::kCenter,
+            builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCenter,
             InterpolationType::kLinear, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear, ast::InterpolationSampling::kCentroid,
+            builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCentroid,
             InterpolationType::kLinear, InterpolationSampling::kCentroid},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear, ast::InterpolationSampling::kSample,
+            builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kSample,
             InterpolationType::kLinear, InterpolationSampling::kSample},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear, ast::InterpolationSampling::kUndefined,
+            builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kUndefined,
             InterpolationType::kLinear, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kFlat, ast::InterpolationSampling::kUndefined,
+            builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kUndefined,
             InterpolationType::kFlat, InterpolationSampling::kNone}));
 
 TEST_F(InspectorGetOverrideDefaultValuesTest, Bool) {
@@ -1655,8 +1655,8 @@
 
 TEST_F(InspectorGetStorageSizeTest, Simple_NonStruct) {
     AddUniformBuffer("ub_var", ty.i32(), 0, 0);
-    AddStorageBuffer("sb_var", ty.i32(), type::Access::kReadWrite, 1, 0);
-    AddStorageBuffer("rosb_var", ty.i32(), type::Access::kRead, 1, 1);
+    AddStorageBuffer("sb_var", ty.i32(), builtin::Access::kReadWrite, 1, 0);
+    AddStorageBuffer("rosb_var", ty.i32(), builtin::Access::kRead, 1, 1);
     Func("ep_func", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("ub", Expr("ub_var"))),
@@ -1687,7 +1687,7 @@
     auto sb = MakeStorageBufferTypes("sb_type", utils::Vector{
                                                     ty.i32(),
                                                 });
-    AddStorageBuffer("sb_var", sb(), type::Access::kReadWrite, 1, 0);
+    AddStorageBuffer("sb_var", sb(), builtin::Access::kReadWrite, 1, 0);
     MakeStructVariableReferenceBodyFunction("sb_func", "sb_var",
                                             utils::Vector{
                                                 MemberInfo{0, ty.i32()},
@@ -1696,7 +1696,7 @@
     auto ro_sb = MakeStorageBufferTypes("rosb_type", utils::Vector{
                                                          ty.i32(),
                                                      });
-    AddStorageBuffer("rosb_var", ro_sb(), type::Access::kRead, 1, 1);
+    AddStorageBuffer("rosb_var", ro_sb(), builtin::Access::kRead, 1, 1);
     MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
                                             utils::Vector{
                                                 MemberInfo{0, ty.i32()},
@@ -1774,7 +1774,7 @@
     auto sb = MakeStorageBufferTypes("sb_type", utils::Vector{
                                                     ty.i32(),
                                                 });
-    AddStorageBuffer("sb_var", sb(), type::Access::kReadWrite, 1, 0);
+    AddStorageBuffer("sb_var", sb(), builtin::Access::kReadWrite, 1, 0);
     MakeStructVariableReferenceBodyFunction("sb_func", "sb_var",
                                             utils::Vector{
                                                 MemberInfo{0, ty.i32()},
@@ -1783,7 +1783,7 @@
     auto ro_sb = MakeStorageBufferTypes("rosb_type", utils::Vector{
                                                          ty.i32(),
                                                      });
-    AddStorageBuffer("rosb_var", ro_sb(), type::Access::kRead, 1, 1);
+    AddStorageBuffer("rosb_var", ro_sb(), builtin::Access::kRead, 1, 1);
     MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
                                             utils::Vector{
                                                 MemberInfo{0, ty.i32()},
@@ -1812,7 +1812,7 @@
          });
 
     auto st_type =
-        MakeStorageTextureTypes(type::TextureDimension::k2d, type::TexelFormat::kR32Uint);
+        MakeStorageTextureTypes(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint);
     AddStorageTexture("st_var", st_type, 4, 0);
     MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<u32>(), utils::Empty);
 
@@ -2140,7 +2140,7 @@
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple_NonStruct) {
-    AddStorageBuffer("foo_sb", ty.i32(), type::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("foo_sb", ty.i32(), builtin::Access::kReadWrite, 0, 0);
     MakePlainGlobalReferenceBodyFunction("sb_func", "foo_sb", ty.i32(), utils::Empty);
 
     MakeCallerBodyFunction("ep_func", utils::Vector{std::string("sb_func")},
@@ -2165,7 +2165,7 @@
     auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
                                                                   ty.i32(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kReadWrite, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2196,7 +2196,7 @@
                                                                   ty.u32(),
                                                                   ty.f32(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kReadWrite, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2229,9 +2229,9 @@
                                                                 ty.u32(),
                                                                 ty.f32(),
                                                             });
-    AddStorageBuffer("sb_foo", sb_struct_type(), type::Access::kReadWrite, 0, 0);
-    AddStorageBuffer("sb_bar", sb_struct_type(), type::Access::kReadWrite, 0, 1);
-    AddStorageBuffer("sb_baz", sb_struct_type(), type::Access::kReadWrite, 2, 0);
+    AddStorageBuffer("sb_foo", sb_struct_type(), builtin::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("sb_bar", sb_struct_type(), builtin::Access::kReadWrite, 0, 1);
+    AddStorageBuffer("sb_baz", sb_struct_type(), builtin::Access::kReadWrite, 2, 0);
 
     auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
         MakeStructVariableReferenceBodyFunction(func_name, var_name,
@@ -2288,7 +2288,7 @@
                                                                   ty.i32(),
                                                                   ty.array<u32, 4>(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kReadWrite, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2318,7 +2318,7 @@
                                                                   ty.i32(),
                                                                   ty.array<u32>(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kReadWrite, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2347,7 +2347,7 @@
     auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
                                                                   ty.vec3<f32>(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kReadWrite, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2373,7 +2373,7 @@
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, NonStructVec3) {
-    AddStorageBuffer("foo_ub", ty.vec3<f32>(), type::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("foo_ub", ty.vec3<f32>(), builtin::Access::kReadWrite, 0, 0);
     MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), utils::Empty);
 
     MakeCallerBodyFunction("ep_func", utils::Vector{std::string("ub_func")},
@@ -2398,7 +2398,7 @@
     auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
                                                                   ty.i32(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kRead, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kRead, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2421,7 +2421,7 @@
     auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
                                                                   ty.i32(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kRead, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kRead, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2452,9 +2452,9 @@
                                                                 ty.u32(),
                                                                 ty.f32(),
                                                             });
-    AddStorageBuffer("sb_foo", sb_struct_type(), type::Access::kRead, 0, 0);
-    AddStorageBuffer("sb_bar", sb_struct_type(), type::Access::kRead, 0, 1);
-    AddStorageBuffer("sb_baz", sb_struct_type(), type::Access::kRead, 2, 0);
+    AddStorageBuffer("sb_foo", sb_struct_type(), builtin::Access::kRead, 0, 0);
+    AddStorageBuffer("sb_bar", sb_struct_type(), builtin::Access::kRead, 0, 1);
+    AddStorageBuffer("sb_baz", sb_struct_type(), builtin::Access::kRead, 2, 0);
 
     auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
         MakeStructVariableReferenceBodyFunction(func_name, var_name,
@@ -2511,7 +2511,7 @@
                                                                   ty.i32(),
                                                                   ty.array<u32, 4>(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kRead, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kRead, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2541,7 +2541,7 @@
                                                                   ty.i32(),
                                                                   ty.array<u32>(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kRead, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kRead, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2570,7 +2570,7 @@
     auto foo_struct_type = MakeStorageBufferTypes("foo_type", utils::Vector{
                                                                   ty.i32(),
                                                               });
-    AddStorageBuffer("foo_sb", foo_struct_type(), type::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("foo_sb", foo_struct_type(), builtin::Access::kReadWrite, 0, 0);
 
     MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                             utils::Vector{
@@ -2899,7 +2899,7 @@
 
     Func("ep", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureLoad", "foo_texture", "foo_coords", "foo_sample_index")),
+             Assign(Phony(), Call("textureLoad", "foo_texture", "foo_coords", "foo_sample_index")),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -2972,7 +2972,7 @@
     ResourceBinding::TextureDimension expected_dim;
     std::tie(dim, expected_dim) = dim_params;
 
-    type::TexelFormat format;
+    builtin::TexelFormat format;
     ResourceBinding::TexelFormat expected_format;
     ResourceBinding::SampledKind expected_kind;
     std::tie(format, expected_format, expected_kind) = format_params;
@@ -3028,52 +3028,52 @@
                                                      ResourceBinding::TextureDimension::k2dArray),
                                      std::make_tuple(type::TextureDimension::k3d,
                                                      ResourceBinding::TextureDimension::k3d)),
-                     testing::Values(std::make_tuple(type::TexelFormat::kR32Float,
+                     testing::Values(std::make_tuple(builtin::TexelFormat::kR32Float,
                                                      ResourceBinding::TexelFormat::kR32Float,
                                                      ResourceBinding::SampledKind::kFloat),
-                                     std::make_tuple(type::TexelFormat::kR32Sint,
+                                     std::make_tuple(builtin::TexelFormat::kR32Sint,
                                                      ResourceBinding::TexelFormat::kR32Sint,
                                                      ResourceBinding::SampledKind::kSInt),
-                                     std::make_tuple(type::TexelFormat::kR32Uint,
+                                     std::make_tuple(builtin::TexelFormat::kR32Uint,
                                                      ResourceBinding::TexelFormat::kR32Uint,
                                                      ResourceBinding::SampledKind::kUInt),
-                                     std::make_tuple(type::TexelFormat::kRg32Float,
+                                     std::make_tuple(builtin::TexelFormat::kRg32Float,
                                                      ResourceBinding::TexelFormat::kRg32Float,
                                                      ResourceBinding::SampledKind::kFloat),
-                                     std::make_tuple(type::TexelFormat::kRg32Sint,
+                                     std::make_tuple(builtin::TexelFormat::kRg32Sint,
                                                      ResourceBinding::TexelFormat::kRg32Sint,
                                                      ResourceBinding::SampledKind::kSInt),
-                                     std::make_tuple(type::TexelFormat::kRg32Uint,
+                                     std::make_tuple(builtin::TexelFormat::kRg32Uint,
                                                      ResourceBinding::TexelFormat::kRg32Uint,
                                                      ResourceBinding::SampledKind::kUInt),
-                                     std::make_tuple(type::TexelFormat::kRgba16Float,
+                                     std::make_tuple(builtin::TexelFormat::kRgba16Float,
                                                      ResourceBinding::TexelFormat::kRgba16Float,
                                                      ResourceBinding::SampledKind::kFloat),
-                                     std::make_tuple(type::TexelFormat::kRgba16Sint,
+                                     std::make_tuple(builtin::TexelFormat::kRgba16Sint,
                                                      ResourceBinding::TexelFormat::kRgba16Sint,
                                                      ResourceBinding::SampledKind::kSInt),
-                                     std::make_tuple(type::TexelFormat::kRgba16Uint,
+                                     std::make_tuple(builtin::TexelFormat::kRgba16Uint,
                                                      ResourceBinding::TexelFormat::kRgba16Uint,
                                                      ResourceBinding::SampledKind::kUInt),
-                                     std::make_tuple(type::TexelFormat::kRgba32Float,
+                                     std::make_tuple(builtin::TexelFormat::kRgba32Float,
                                                      ResourceBinding::TexelFormat::kRgba32Float,
                                                      ResourceBinding::SampledKind::kFloat),
-                                     std::make_tuple(type::TexelFormat::kRgba32Sint,
+                                     std::make_tuple(builtin::TexelFormat::kRgba32Sint,
                                                      ResourceBinding::TexelFormat::kRgba32Sint,
                                                      ResourceBinding::SampledKind::kSInt),
-                                     std::make_tuple(type::TexelFormat::kRgba32Uint,
+                                     std::make_tuple(builtin::TexelFormat::kRgba32Uint,
                                                      ResourceBinding::TexelFormat::kRgba32Uint,
                                                      ResourceBinding::SampledKind::kUInt),
-                                     std::make_tuple(type::TexelFormat::kRgba8Sint,
+                                     std::make_tuple(builtin::TexelFormat::kRgba8Sint,
                                                      ResourceBinding::TexelFormat::kRgba8Sint,
                                                      ResourceBinding::SampledKind::kSInt),
-                                     std::make_tuple(type::TexelFormat::kRgba8Snorm,
+                                     std::make_tuple(builtin::TexelFormat::kRgba8Snorm,
                                                      ResourceBinding::TexelFormat::kRgba8Snorm,
                                                      ResourceBinding::SampledKind::kFloat),
-                                     std::make_tuple(type::TexelFormat::kRgba8Uint,
+                                     std::make_tuple(builtin::TexelFormat::kRgba8Uint,
                                                      ResourceBinding::TexelFormat::kRgba8Uint,
                                                      ResourceBinding::SampledKind::kUInt),
-                                     std::make_tuple(type::TexelFormat::kRgba8Unorm,
+                                     std::make_tuple(builtin::TexelFormat::kRgba8Unorm,
                                                      ResourceBinding::TexelFormat::kRgba8Unorm,
                                                      ResourceBinding::SampledKind::kFloat))));
 
@@ -3083,7 +3083,7 @@
 
     Func("ep", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "dt")),
+             Assign(Phony(), Call("textureDimensions", "dt")),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -3120,7 +3120,7 @@
 
     Func("ep", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Assign(Phony(), Call("textureDimensions", "tex")),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -3144,7 +3144,7 @@
 
     Func("ep", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "et")),
+             Assign(Phony(), Call("textureDimensions", "et")),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
diff --git a/src/tint/inspector/resource_binding.cc b/src/tint/inspector/resource_binding.cc
index 91e5daf..9b0dc83 100644
--- a/src/tint/inspector/resource_binding.cc
+++ b/src/tint/inspector/resource_binding.cc
@@ -71,43 +71,43 @@
 }
 
 ResourceBinding::TexelFormat TypeTexelFormatToResourceBindingTexelFormat(
-    const type::TexelFormat& image_format) {
+    const builtin::TexelFormat& image_format) {
     switch (image_format) {
-        case type::TexelFormat::kBgra8Unorm:
+        case builtin::TexelFormat::kBgra8Unorm:
             return ResourceBinding::TexelFormat::kBgra8Unorm;
-        case type::TexelFormat::kR32Uint:
+        case builtin::TexelFormat::kR32Uint:
             return ResourceBinding::TexelFormat::kR32Uint;
-        case type::TexelFormat::kR32Sint:
+        case builtin::TexelFormat::kR32Sint:
             return ResourceBinding::TexelFormat::kR32Sint;
-        case type::TexelFormat::kR32Float:
+        case builtin::TexelFormat::kR32Float:
             return ResourceBinding::TexelFormat::kR32Float;
-        case type::TexelFormat::kRgba8Unorm:
+        case builtin::TexelFormat::kRgba8Unorm:
             return ResourceBinding::TexelFormat::kRgba8Unorm;
-        case type::TexelFormat::kRgba8Snorm:
+        case builtin::TexelFormat::kRgba8Snorm:
             return ResourceBinding::TexelFormat::kRgba8Snorm;
-        case type::TexelFormat::kRgba8Uint:
+        case builtin::TexelFormat::kRgba8Uint:
             return ResourceBinding::TexelFormat::kRgba8Uint;
-        case type::TexelFormat::kRgba8Sint:
+        case builtin::TexelFormat::kRgba8Sint:
             return ResourceBinding::TexelFormat::kRgba8Sint;
-        case type::TexelFormat::kRg32Uint:
+        case builtin::TexelFormat::kRg32Uint:
             return ResourceBinding::TexelFormat::kRg32Uint;
-        case type::TexelFormat::kRg32Sint:
+        case builtin::TexelFormat::kRg32Sint:
             return ResourceBinding::TexelFormat::kRg32Sint;
-        case type::TexelFormat::kRg32Float:
+        case builtin::TexelFormat::kRg32Float:
             return ResourceBinding::TexelFormat::kRg32Float;
-        case type::TexelFormat::kRgba16Uint:
+        case builtin::TexelFormat::kRgba16Uint:
             return ResourceBinding::TexelFormat::kRgba16Uint;
-        case type::TexelFormat::kRgba16Sint:
+        case builtin::TexelFormat::kRgba16Sint:
             return ResourceBinding::TexelFormat::kRgba16Sint;
-        case type::TexelFormat::kRgba16Float:
+        case builtin::TexelFormat::kRgba16Float:
             return ResourceBinding::TexelFormat::kRgba16Float;
-        case type::TexelFormat::kRgba32Uint:
+        case builtin::TexelFormat::kRgba32Uint:
             return ResourceBinding::TexelFormat::kRgba32Uint;
-        case type::TexelFormat::kRgba32Sint:
+        case builtin::TexelFormat::kRgba32Sint:
             return ResourceBinding::TexelFormat::kRgba32Sint;
-        case type::TexelFormat::kRgba32Float:
+        case builtin::TexelFormat::kRgba32Float:
             return ResourceBinding::TexelFormat::kRgba32Float;
-        case type::TexelFormat::kUndefined:
+        case builtin::TexelFormat::kUndefined:
             return ResourceBinding::TexelFormat::kNone;
     }
     return ResourceBinding::TexelFormat::kNone;
diff --git a/src/tint/inspector/resource_binding.h b/src/tint/inspector/resource_binding.h
index 4c1e0c7..69e1832 100644
--- a/src/tint/inspector/resource_binding.h
+++ b/src/tint/inspector/resource_binding.h
@@ -17,7 +17,7 @@
 
 #include <cstdint>
 
-#include "src/tint/type/texel_format.h"
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/type/texture_dimension.h"
 #include "src/tint/type/type.h"
 
@@ -116,12 +116,12 @@
 /// @returns the publicly visible equivalent
 ResourceBinding::SampledKind BaseTypeToSampledKind(const type::Type* base_type);
 
-/// Convert from internal type::TexelFormat to public
+/// Convert from internal builtin::TexelFormat to public
 /// ResourceBinding::TexelFormat
 /// @param image_format internal value to convert from
 /// @returns the publicly visible equivalent
 ResourceBinding::TexelFormat TypeTexelFormatToResourceBindingTexelFormat(
-    const type::TexelFormat& image_format);
+    const builtin::TexelFormat& image_format);
 
 }  // namespace tint::inspector
 
diff --git a/src/tint/inspector/test_inspector_builder.cc b/src/tint/inspector/test_inspector_builder.cc
index e73c6f5..ad576b9 100644
--- a/src/tint/inspector/test_inspector_builder.cc
+++ b/src/tint/inspector/test_inspector_builder.cc
@@ -125,19 +125,20 @@
                                         ast::Type type,
                                         uint32_t group,
                                         uint32_t binding) {
-    GlobalVar(name, type, type::AddressSpace::kUniform, Binding(AInt(binding)), Group(AInt(group)));
+    GlobalVar(name, type, builtin::AddressSpace::kUniform, Binding(AInt(binding)),
+              Group(AInt(group)));
 }
 
 void InspectorBuilder::AddWorkgroupStorage(const std::string& name, ast::Type type) {
-    GlobalVar(name, type, type::AddressSpace::kWorkgroup);
+    GlobalVar(name, type, builtin::AddressSpace::kWorkgroup);
 }
 
 void InspectorBuilder::AddStorageBuffer(const std::string& name,
                                         ast::Type type,
-                                        type::Access access,
+                                        builtin::Access access,
                                         uint32_t group,
                                         uint32_t binding) {
-    GlobalVar(name, type, type::AddressSpace::kStorage, access, Binding(AInt(binding)),
+    GlobalVar(name, type, builtin::AddressSpace::kStorage, access, Binding(AInt(binding)),
               Group(AInt(group)));
 }
 
@@ -189,7 +190,7 @@
 }
 
 void InspectorBuilder::AddGlobalVariable(const std::string& name, ast::Type type) {
-    GlobalVar(name, type, type::AddressSpace::kPrivate);
+    GlobalVar(name, type, builtin::AddressSpace::kPrivate);
 }
 
 const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
@@ -278,8 +279,8 @@
 }
 
 ast::Type InspectorBuilder::MakeStorageTextureTypes(type::TextureDimension dim,
-                                                    type::TexelFormat format) {
-    return ty.storage_texture(dim, format, type::Access::kWrite);
+                                                    builtin::TexelFormat format) {
+    return ty.storage_texture(dim, format, builtin::Access::kWrite);
 }
 
 void InspectorBuilder::AddStorageTexture(const std::string& name,
diff --git a/src/tint/inspector/test_inspector_builder.h b/src/tint/inspector/test_inspector_builder.h
index 1d99863..0fa21b7 100644
--- a/src/tint/inspector/test_inspector_builder.h
+++ b/src/tint/inspector/test_inspector_builder.h
@@ -182,7 +182,7 @@
     /// @param binding the binding number to use for the storage buffer
     void AddStorageBuffer(const std::string& name,
                           ast::Type type,
-                          type::Access access,
+                          builtin::Access access,
                           uint32_t group,
                           uint32_t binding);
 
@@ -290,7 +290,7 @@
     /// @param dim the texture dimension of the storage texture
     /// @param format the texel format of the storage texture
     /// @returns the storage texture type
-    ast::Type MakeStorageTextureTypes(type::TextureDimension dim, type::TexelFormat format);
+    ast::Type MakeStorageTextureTypes(type::TextureDimension dim, builtin::TexelFormat format);
 
     /// Adds a storage texture variable to the program
     /// @param name the name of the variable
diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def
index 5985921..826a667 100644
--- a/src/tint/intrinsics.def
+++ b/src/tint/intrinsics.def
@@ -37,7 +37,7 @@
   num_workgroups
   sample_index
   sample_mask
-  @internal point_size
+  __point_size
 }
 
 // https://gpuweb.github.io/gpuweb/wgsl/#filterable-triggering-rules
@@ -74,16 +74,15 @@
 
 // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
 enum address_space {
-  @internal none
   function
   private
   workgroup
   uniform
   storage
   push_constant
+  __in
+  __out
   @internal handle
-  @internal in
-  @internal out
 }
 
 // https://gpuweb.github.io/gpuweb/wgsl/#memory-access-mode
@@ -212,6 +211,29 @@
   texture_external
 }
 
+// https://gpuweb.github.io/gpuweb/wgsl/#attributes
+// Notes:
+//  * `diagnostic` is listed, even though it is a keyword, so it appears in suggested alternatives
+//  * `const` is not listed here as it can not be written in user programs and should not show up
+//     in error messages
+enum attribute {
+  align
+  binding
+  builtin
+  compute
+  diagnostic
+  fragment
+  group
+  id
+  interpolate
+  invariant
+  location
+  must_use
+  size
+  vertex
+  workgroup_size
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // WGSL primitive types                                                       //
 // Types may be decorated with @precedence(N) to prioritize which type        //
@@ -512,280 +534,280 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 // https://gpuweb.github.io/gpuweb/wgsl/#builtin-functions
-@const fn abs<T: fia_fiu32_f16>(T) -> T
-@const fn abs<N: num, T: fia_fiu32_f16>(vec<N, T>) -> vec<N, T>
-@const fn acos<T: fa_f32_f16>(@test_value(0.96891242171) T) -> T
-@const fn acos<N: num, T: fa_f32_f16>(@test_value(0.96891242171) vec<N, T>) -> vec<N, T>
-@const fn acosh<T: fa_f32_f16>(@test_value(2.0) T) -> T
-@const fn acosh<N: num, T: fa_f32_f16>(@test_value(2.0) vec<N, T>) -> vec<N, T>
-@const fn all(bool) -> bool
-@const fn all<N: num>(vec<N, bool>) -> bool
-@const fn any(bool) -> bool
-@const fn any<N: num>(vec<N, bool>) -> bool
-fn arrayLength<T, A: access>(ptr<storage, array<T>, A>) -> u32
-@const fn asin<T: fa_f32_f16>(@test_value(0.479425538604) T) -> T
-@const fn asin<N: num, T: fa_f32_f16>(@test_value(0.479425538604) vec<N, T>) -> vec<N, T>
-@const fn asinh<T: fa_f32_f16>(T) -> T
-@const fn asinh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn atan<T: fa_f32_f16>(T) -> T
-@const fn atan<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn atan2<T: fa_f32_f16>(T, T) -> T
-@const fn atan2<T: fa_f32_f16, N: num>(vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn atanh<T: fa_f32_f16>(@test_value(0.5) T) -> T
-@const fn atanh<N: num, T: fa_f32_f16>(@test_value(0.5) vec<N, T>) -> vec<N, T>
-@const fn ceil<T: fa_f32_f16>(@test_value(1.5) T) -> T
-@const fn ceil<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
-@const fn clamp<T: fia_fiu32_f16>(T, T, T) -> T
-@const fn clamp<T: fia_fiu32_f16, N: num>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn cos<T: fa_f32_f16>(@test_value(0) T) -> T
-@const fn cos<N: num, T: fa_f32_f16>(@test_value(0) vec<N, T>) -> vec<N, T>
-@const fn cosh<T: fa_f32_f16>(@test_value(0) T) -> T
-@const fn cosh<N: num, T: fa_f32_f16>(@test_value(0) vec<N, T>) -> vec<N, T>
-@const fn countLeadingZeros<T: iu32>(T) -> T
-@const fn countLeadingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-@const fn countOneBits<T: iu32>(T) -> T
-@const fn countOneBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-@const fn countTrailingZeros<T: iu32>(T) -> T
-@const fn countTrailingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-@const fn cross<T: fa_f32_f16>(vec3<T>, vec3<T>) -> vec3<T>
-@const fn degrees<T: fa_f32_f16>(T) -> T
-@const fn degrees<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn determinant<N: num, T: fa_f32_f16>(mat<N, N, T>) -> T
-@const fn distance<T: fa_f32_f16>(T, T) -> T
-@const fn distance<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> T
-@const fn dot<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> T
-fn dot4I8Packed(u32, u32) -> i32
-fn dot4U8Packed(u32, u32) -> u32
-@stage("fragment") fn dpdx(f32) -> f32
-@stage("fragment") fn dpdx<N: num>(vec<N, f32>) -> vec<N, f32>
-@stage("fragment") fn dpdxCoarse(f32) -> f32
-@stage("fragment") fn dpdxCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
-@stage("fragment") fn dpdxFine(f32) -> f32
-@stage("fragment") fn dpdxFine<N: num>(vec<N, f32>) -> vec<N, f32>
-@stage("fragment") fn dpdy(f32) -> f32
-@stage("fragment") fn dpdy<N: num>(vec<N, f32>) -> vec<N, f32>
-@stage("fragment") fn dpdyCoarse(f32) -> f32
-@stage("fragment") fn dpdyCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
-@stage("fragment") fn dpdyFine(f32) -> f32
-@stage("fragment") fn dpdyFine<N: num>(vec<N, f32>) -> vec<N, f32>
-@const fn exp<T: fa_f32_f16>(T) -> T
-@const fn exp<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn exp2<T: fa_f32_f16>(T) -> T
-@const fn exp2<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn extractBits<T: iu32>(T, u32, u32) -> T
-@const fn extractBits<N: num, T: iu32>(vec<N, T>, u32, u32) -> vec<N, T>
-@const fn faceForward<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn firstLeadingBit<T: iu32>(T) -> T
-@const fn firstLeadingBit<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-@const fn firstTrailingBit<T: iu32>(T) -> T
-@const fn firstTrailingBit<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-@const fn floor<T: fa_f32_f16>(@test_value(1.5) T) -> T
-@const fn floor<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
-@const fn fma<T: fa_f32_f16>(T, T, T) -> T
-@const fn fma<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn fract<T: fa_f32_f16>(@test_value(1.25) T) -> T
-@const fn fract<N: num, T: fa_f32_f16>(@test_value(1.25) vec<N, T>) -> vec<N, T>
-@const fn frexp<T: fa_f32_f16>(T) -> __frexp_result<T>
-@const fn frexp<N: num, T: fa_f32_f16>(vec<N, T>) -> __frexp_result_vec<N, T>
-@stage("fragment") fn fwidth(f32) -> f32
-@stage("fragment") fn fwidth<N: num>(vec<N, f32>) -> vec<N, f32>
-@stage("fragment") fn fwidthCoarse(f32) -> f32
-@stage("fragment") fn fwidthCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
-@stage("fragment") fn fwidthFine(f32) -> f32
-@stage("fragment") fn fwidthFine<N: num>(vec<N, f32>) -> vec<N, f32>
-@const fn insertBits<T: iu32>(T, T, u32, u32) -> T
-@const fn insertBits<N: num, T: iu32>(vec<N, T>, vec<N, T>, u32, u32) -> vec<N, T>
-@const fn inverseSqrt<T: fa_f32_f16>(T) -> T
-@const fn inverseSqrt<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn ldexp<T: fa_f32_f16, U: ia_i32>(T, U) -> T
-@const fn ldexp<N: num, T: fa_f32_f16, U: ia_i32>(vec<N, T>, vec<N, U>) -> vec<N, T>
-@const fn length<T: fa_f32_f16>(@test_value(0.0) T) -> T
-@const fn length<N: num, T: fa_f32_f16>(@test_value(0.0) vec<N, T>) -> T
-@const fn log<T: fa_f32_f16>(T) -> T
-@const fn log<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn log2<T: fa_f32_f16>(T) -> T
-@const fn log2<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn max<T: fia_fiu32_f16>(T, T) -> T
-@const fn max<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn min<T: fia_fiu32_f16>(T, T) -> T
-@const fn min<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn mix<T: fa_f32_f16>(T, T, T) -> T
-@const fn mix<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn mix<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T>
-@const fn modf<T: fa_f32_f16>(@test_value(-1.5) T) -> __modf_result<T>
-@const fn modf<N: num, T: fa_f32_f16>(@test_value(-1.5) vec<N, T>) -> __modf_result_vec<N, T>
-@const fn normalize<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn pack2x16float(vec2<f32>) -> u32
-@const fn pack2x16snorm(vec2<f32>) -> u32
-@const fn pack2x16unorm(vec2<f32>) -> u32
-@const fn pack4x8snorm(vec4<f32>) -> u32
-@const fn pack4x8unorm(vec4<f32>) -> u32
-@const fn pow<T: fa_f32_f16>(T, T) -> T
-@const fn pow<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn quantizeToF16(f32) -> f32
-@const fn quantizeToF16<N: num>(vec<N, f32>) -> vec<N, f32>
-@const fn radians<T: fa_f32_f16>(T) -> T
-@const fn radians<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn reflect<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
-@const fn refract<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T>
-@const fn reverseBits<T: iu32>(T) -> T
-@const fn reverseBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-@const fn round<T: fa_f32_f16>(@test_value(3.4) T) -> T
-@const fn round<N: num, T: fa_f32_f16>(@test_value(3.4) vec<N, T>) -> vec<N, T>
-@const fn saturate<T: fa_f32_f16>(@test_value(2) T) -> T
-@const fn saturate<T: fa_f32_f16, N: num>(@test_value(2) vec<N, T>) -> vec<N, T>
-@const("select_bool") fn select<T: scalar>(T, T, bool) -> T
-@const("select_bool") fn select<T: scalar, N: num>(vec<N, T>, vec<N, T>, bool) -> vec<N, T>
-@const("select_boolvec") fn select<N: num, T: scalar>(vec<N, T>, vec<N, T>, vec<N, bool>) -> vec<N, T>
-@const fn sign<T: fia_fi32_f16>(T) -> T
-@const fn sign<N: num, T: fia_fi32_f16>(vec<N, T>) -> vec<N, T>
-@const fn sin<T: fa_f32_f16>(T) -> T
-@const fn sin<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn sinh<T: fa_f32_f16>(T) -> T
-@const fn sinh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn smoothstep<T: fa_f32_f16>(@test_value(2) T, @test_value(4) T, @test_value(3) T) -> T
-@const fn smoothstep<N: num, T: fa_f32_f16>(@test_value(2) vec<N, T>, @test_value(4) vec<N, T>, @test_value(3) vec<N, T>) -> vec<N, T>
-@const fn sqrt<T: fa_f32_f16>(T) -> T
-@const fn sqrt<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn step<T: fa_f32_f16>(T, T) -> T
-@const fn step<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn abs<T: fia_fiu32_f16>(T) -> T
+@must_use @const fn abs<N: num, T: fia_fiu32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn acos<T: fa_f32_f16>(@test_value(0.96891242171) T) -> T
+@must_use @const fn acos<N: num, T: fa_f32_f16>(@test_value(0.96891242171) vec<N, T>) -> vec<N, T>
+@must_use @const fn acosh<T: fa_f32_f16>(@test_value(2.0) T) -> T
+@must_use @const fn acosh<N: num, T: fa_f32_f16>(@test_value(2.0) vec<N, T>) -> vec<N, T>
+@must_use @const fn all(bool) -> bool
+@must_use @const fn all<N: num>(vec<N, bool>) -> bool
+@must_use @const fn any(bool) -> bool
+@must_use @const fn any<N: num>(vec<N, bool>) -> bool
+@must_use fn arrayLength<T, A: access>(ptr<storage, array<T>, A>) -> u32
+@must_use @const fn asin<T: fa_f32_f16>(@test_value(0.479425538604) T) -> T
+@must_use @const fn asin<N: num, T: fa_f32_f16>(@test_value(0.479425538604) vec<N, T>) -> vec<N, T>
+@must_use @const fn asinh<T: fa_f32_f16>(T) -> T
+@must_use @const fn asinh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn atan<T: fa_f32_f16>(T) -> T
+@must_use @const fn atan<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn atan2<T: fa_f32_f16>(T, T) -> T
+@must_use @const fn atan2<T: fa_f32_f16, N: num>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn atanh<T: fa_f32_f16>(@test_value(0.5) T) -> T
+@must_use @const fn atanh<N: num, T: fa_f32_f16>(@test_value(0.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn ceil<T: fa_f32_f16>(@test_value(1.5) T) -> T
+@must_use @const fn ceil<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn clamp<T: fia_fiu32_f16>(T, T, T) -> T
+@must_use @const fn clamp<T: fia_fiu32_f16, N: num>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn cos<T: fa_f32_f16>(@test_value(0) T) -> T
+@must_use @const fn cos<N: num, T: fa_f32_f16>(@test_value(0) vec<N, T>) -> vec<N, T>
+@must_use @const fn cosh<T: fa_f32_f16>(@test_value(0) T) -> T
+@must_use @const fn cosh<N: num, T: fa_f32_f16>(@test_value(0) vec<N, T>) -> vec<N, T>
+@must_use @const fn countLeadingZeros<T: iu32>(T) -> T
+@must_use @const fn countLeadingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn countOneBits<T: iu32>(T) -> T
+@must_use @const fn countOneBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn countTrailingZeros<T: iu32>(T) -> T
+@must_use @const fn countTrailingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn cross<T: fa_f32_f16>(vec3<T>, vec3<T>) -> vec3<T>
+@must_use @const fn degrees<T: fa_f32_f16>(T) -> T
+@must_use @const fn degrees<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn determinant<N: num, T: fa_f32_f16>(mat<N, N, T>) -> T
+@must_use @const fn distance<T: fa_f32_f16>(T, T) -> T
+@must_use @const fn distance<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> T
+@must_use @const fn dot<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> T
+@must_use fn dot4I8Packed(u32, u32) -> i32
+@must_use fn dot4U8Packed(u32, u32) -> u32
+@must_use @stage("fragment") fn dpdx(f32) -> f32
+@must_use @stage("fragment") fn dpdx<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdxCoarse(f32) -> f32
+@must_use @stage("fragment") fn dpdxCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdxFine(f32) -> f32
+@must_use @stage("fragment") fn dpdxFine<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdy(f32) -> f32
+@must_use @stage("fragment") fn dpdy<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdyCoarse(f32) -> f32
+@must_use @stage("fragment") fn dpdyCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdyFine(f32) -> f32
+@must_use @stage("fragment") fn dpdyFine<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @const fn exp<T: fa_f32_f16>(T) -> T
+@must_use @const fn exp<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn exp2<T: fa_f32_f16>(T) -> T
+@must_use @const fn exp2<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn extractBits<T: iu32>(T, u32, u32) -> T
+@must_use @const fn extractBits<N: num, T: iu32>(vec<N, T>, u32, u32) -> vec<N, T>
+@must_use @const fn faceForward<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn firstLeadingBit<T: iu32>(T) -> T
+@must_use @const fn firstLeadingBit<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn firstTrailingBit<T: iu32>(T) -> T
+@must_use @const fn firstTrailingBit<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn floor<T: fa_f32_f16>(@test_value(1.5) T) -> T
+@must_use @const fn floor<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn fma<T: fa_f32_f16>(T, T, T) -> T
+@must_use @const fn fma<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn fract<T: fa_f32_f16>(@test_value(1.25) T) -> T
+@must_use @const fn fract<N: num, T: fa_f32_f16>(@test_value(1.25) vec<N, T>) -> vec<N, T>
+@must_use @const fn frexp<T: fa_f32_f16>(T) -> __frexp_result<T>
+@must_use @const fn frexp<N: num, T: fa_f32_f16>(vec<N, T>) -> __frexp_result_vec<N, T>
+@must_use @stage("fragment") fn fwidth(f32) -> f32
+@must_use @stage("fragment") fn fwidth<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn fwidthCoarse(f32) -> f32
+@must_use @stage("fragment") fn fwidthCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn fwidthFine(f32) -> f32
+@must_use @stage("fragment") fn fwidthFine<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @const fn insertBits<T: iu32>(T, T, u32, u32) -> T
+@must_use @const fn insertBits<N: num, T: iu32>(vec<N, T>, vec<N, T>, u32, u32) -> vec<N, T>
+@must_use @const fn inverseSqrt<T: fa_f32_f16>(T) -> T
+@must_use @const fn inverseSqrt<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn ldexp<T: fa_f32_f16, U: ia_i32>(T, U) -> T
+@must_use @const fn ldexp<N: num, T: fa_f32_f16, U: ia_i32>(vec<N, T>, vec<N, U>) -> vec<N, T>
+@must_use @const fn length<T: fa_f32_f16>(@test_value(0.0) T) -> T
+@must_use @const fn length<N: num, T: fa_f32_f16>(@test_value(0.0) vec<N, T>) -> T
+@must_use @const fn log<T: fa_f32_f16>(T) -> T
+@must_use @const fn log<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn log2<T: fa_f32_f16>(T) -> T
+@must_use @const fn log2<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn max<T: fia_fiu32_f16>(T, T) -> T
+@must_use @const fn max<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn min<T: fia_fiu32_f16>(T, T) -> T
+@must_use @const fn min<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn mix<T: fa_f32_f16>(T, T, T) -> T
+@must_use @const fn mix<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn mix<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T>
+@must_use @const fn modf<T: fa_f32_f16>(@test_value(-1.5) T) -> __modf_result<T>
+@must_use @const fn modf<N: num, T: fa_f32_f16>(@test_value(-1.5) vec<N, T>) -> __modf_result_vec<N, T>
+@must_use @const fn normalize<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn pack2x16float(vec2<f32>) -> u32
+@must_use @const fn pack2x16snorm(vec2<f32>) -> u32
+@must_use @const fn pack2x16unorm(vec2<f32>) -> u32
+@must_use @const fn pack4x8snorm(vec4<f32>) -> u32
+@must_use @const fn pack4x8unorm(vec4<f32>) -> u32
+@must_use @const fn pow<T: fa_f32_f16>(T, T) -> T
+@must_use @const fn pow<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn quantizeToF16(f32) -> f32
+@must_use @const fn quantizeToF16<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @const fn radians<T: fa_f32_f16>(T) -> T
+@must_use @const fn radians<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn reflect<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn refract<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T>
+@must_use @const fn reverseBits<T: iu32>(T) -> T
+@must_use @const fn reverseBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn round<T: fa_f32_f16>(@test_value(3.4) T) -> T
+@must_use @const fn round<N: num, T: fa_f32_f16>(@test_value(3.4) vec<N, T>) -> vec<N, T>
+@must_use @const fn saturate<T: fa_f32_f16>(@test_value(2) T) -> T
+@must_use @const fn saturate<T: fa_f32_f16, N: num>(@test_value(2) vec<N, T>) -> vec<N, T>
+@must_use @const("select_bool") fn select<T: scalar>(T, T, bool) -> T
+@must_use @const("select_bool") fn select<T: scalar, N: num>(vec<N, T>, vec<N, T>, bool) -> vec<N, T>
+@must_use @const("select_boolvec") fn select<N: num, T: scalar>(vec<N, T>, vec<N, T>, vec<N, bool>) -> vec<N, T>
+@must_use @const fn sign<T: fia_fi32_f16>(T) -> T
+@must_use @const fn sign<N: num, T: fia_fi32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn sin<T: fa_f32_f16>(@test_value(1.57079632679) T) -> T
+@must_use @const fn sin<N: num, T: fa_f32_f16>(@test_value(1.57079632679) vec<N, T>) -> vec<N, T>
+@must_use @const fn sinh<T: fa_f32_f16>(T) -> T
+@must_use @const fn sinh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn smoothstep<T: fa_f32_f16>(@test_value(2) T, @test_value(4) T, @test_value(3) T) -> T
+@must_use @const fn smoothstep<N: num, T: fa_f32_f16>(@test_value(2) vec<N, T>, @test_value(4) vec<N, T>, @test_value(3) vec<N, T>) -> vec<N, T>
+@must_use @const fn sqrt<T: fa_f32_f16>(T) -> T
+@must_use @const fn sqrt<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn step<T: fa_f32_f16>(T, T) -> T
+@must_use @const fn step<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
 @stage("compute") fn storageBarrier()
-@const fn tan<T: fa_f32_f16>(T) -> T
-@const fn tan<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn tanh<T: fa_f32_f16>(T) -> T
-@const fn tanh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
-@const fn transpose<M: num, N: num, T: fa_f32_f16>(mat<M, N, T>) -> mat<N, M, T>
-@const fn trunc<T: fa_f32_f16>(@test_value(1.5) T) -> T
-@const fn trunc<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
-@const fn unpack2x16float(u32) -> vec2<f32>
-@const fn unpack2x16snorm(u32) -> vec2<f32>
-@const fn unpack2x16unorm(u32) -> vec2<f32>
-@const fn unpack4x8snorm(u32) -> vec4<f32>
-@const fn unpack4x8unorm(u32) -> vec4<f32>
+@must_use @const fn tan<T: fa_f32_f16>(T) -> T
+@must_use @const fn tan<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn tanh<T: fa_f32_f16>(T) -> T
+@must_use @const fn tanh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn transpose<M: num, N: num, T: fa_f32_f16>(mat<M, N, T>) -> mat<N, M, T>
+@must_use @const fn trunc<T: fa_f32_f16>(@test_value(1.5) T) -> T
+@must_use @const fn trunc<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn unpack2x16float(u32) -> vec2<f32>
+@must_use @const fn unpack2x16snorm(u32) -> vec2<f32>
+@must_use @const fn unpack2x16unorm(u32) -> vec2<f32>
+@must_use @const fn unpack4x8snorm(u32) -> vec4<f32>
+@must_use @const fn unpack4x8unorm(u32) -> vec4<f32>
 @stage("compute") fn workgroupBarrier()
-@stage("compute") fn workgroupUniformLoad<T>(ptr<workgroup, T, read_write>) -> T
+@must_use @stage("compute") fn workgroupUniformLoad<T>(ptr<workgroup, T, read_write>) -> T
 
-fn textureDimensions<T: fiu32>(texture: texture_1d<T>) -> u32
-fn textureDimensions<T: fiu32, L: iu32>(texture: texture_1d<T>, level: L) -> u32
-fn textureDimensions<T: fiu32>(texture: texture_2d<T>) -> vec2<u32>
-fn textureDimensions<T: fiu32, L: iu32>(texture: texture_2d<T>, level: L) -> vec2<u32>
-fn textureDimensions<T: fiu32>(texture: texture_2d_array<T>) -> vec2<u32>
-fn textureDimensions<T: fiu32, L: iu32>(texture: texture_2d_array<T>, level: L) -> vec2<u32>
-fn textureDimensions<T: fiu32>(texture: texture_3d<T>) -> vec3<u32>
-fn textureDimensions<T: fiu32, L: iu32>(texture: texture_3d<T>, level: L) -> vec3<u32>
-fn textureDimensions<T: fiu32>(texture: texture_cube<T>) -> vec2<u32>
-fn textureDimensions<T: fiu32, L: iu32>(texture: texture_cube<T>, level: L) -> vec2<u32>
-fn textureDimensions<T: fiu32>(texture: texture_cube_array<T>) -> vec2<u32>
-fn textureDimensions<T: fiu32, L: iu32>(texture: texture_cube_array<T>, level: L) -> vec2<u32>
-fn textureDimensions<T: fiu32>(texture: texture_multisampled_2d<T>) -> vec2<u32>
-fn textureDimensions(texture: texture_depth_2d) -> vec2<u32>
-fn textureDimensions<L: iu32>(texture: texture_depth_2d, level: L) -> vec2<u32>
-fn textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>
-fn textureDimensions<L: iu32>(texture: texture_depth_2d_array, level: L) -> vec2<u32>
-fn textureDimensions(texture: texture_depth_cube) -> vec2<u32>
-fn textureDimensions<L: iu32>(texture: texture_depth_cube, level: L) -> vec2<u32>
-fn textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>
-fn textureDimensions<L: iu32>(texture: texture_depth_cube_array, level: L) -> vec2<u32>
-fn textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>
-fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_1d<F, A>) -> u32
-fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d<F, A>) -> vec2<u32>
-fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d_array<F, A>) -> vec2<u32>
-fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_3d<F, A>) -> vec3<u32>
-fn textureDimensions(texture: texture_external) -> vec2<u32>
-fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>) -> vec4<T>
-fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<T>
-fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<T>
-fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<T>
-fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_cube<T>, sampler: sampler, coords: vec3<f32>) -> vec4<T>
-fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_cube_array<T>, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<T>
-fn textureGather(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
-fn textureGather(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
-fn textureGather<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<f32>
-fn textureGather<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<f32>
-fn textureGather(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
-fn textureGather<A: iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<f32>
-fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> vec4<f32>
-fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32>
-fn textureGatherCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> vec4<f32>
-fn textureGatherCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32>
-fn textureGatherCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> vec4<f32>
-fn textureGatherCompare<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> vec4<f32>
-fn textureNumLayers<T: fiu32>(texture: texture_2d_array<T>) -> u32
-fn textureNumLayers<T: fiu32>(texture: texture_cube_array<T>) -> u32
-fn textureNumLayers(texture: texture_depth_2d_array) -> u32
-fn textureNumLayers(texture: texture_depth_cube_array) -> u32
-fn textureNumLayers<F: texel_format, A: write>(texture: texture_storage_2d_array<F, A>) -> u32
-fn textureNumLevels<T: fiu32>(texture: texture_1d<T>) -> u32
-fn textureNumLevels<T: fiu32>(texture: texture_2d<T>) -> u32
-fn textureNumLevels<T: fiu32>(texture: texture_2d_array<T>) -> u32
-fn textureNumLevels<T: fiu32>(texture: texture_3d<T>) -> u32
-fn textureNumLevels<T: fiu32>(texture: texture_cube<T>) -> u32
-fn textureNumLevels<T: fiu32>(texture: texture_cube_array<T>) -> u32
-fn textureNumLevels(texture: texture_depth_2d) -> u32
-fn textureNumLevels(texture: texture_depth_2d_array) -> u32
-fn textureNumLevels(texture: texture_depth_cube) -> u32
-fn textureNumLevels(texture: texture_depth_cube_array) -> u32
-fn textureNumSamples<T: fiu32>(texture: texture_multisampled_2d<T>) -> u32
-fn textureNumSamples(texture: texture_depth_multisampled_2d) -> u32
-@stage("fragment") fn textureSample(texture: texture_1d<f32>, sampler: sampler, coords: f32) -> vec4<f32>
-@stage("fragment") fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
-@stage("fragment") fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
-@stage("fragment") fn textureSample<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<f32>
-@stage("fragment") fn textureSample<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<f32>
-@stage("fragment") fn textureSample(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
-@stage("fragment") fn textureSample(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, @const offset: vec3<i32>) -> vec4<f32>
-@stage("fragment") fn textureSample(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
-@stage("fragment") fn textureSample<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<f32>
-@stage("fragment") fn textureSample(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>) -> f32
-@stage("fragment") fn textureSample(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> f32
-@stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A) -> f32
-@stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> f32
-@stage("fragment") fn textureSample(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> f32
-@stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A) -> f32
-@stage("fragment") fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32) -> vec4<f32>
-@stage("fragment") fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32, @const offset: vec2<i32>) -> vec4<f32>
-@stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, bias: f32) -> vec4<f32>
-@stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, bias: f32, @const offset: vec2<i32>) -> vec4<f32>
-@stage("fragment") fn textureSampleBias(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32>
-@stage("fragment") fn textureSampleBias(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, bias: f32, @const offset: vec3<i32>) -> vec4<f32>
-@stage("fragment") fn textureSampleBias(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32>
-@stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, bias: f32) -> vec4<f32>
-@stage("fragment") fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32
-@stage("fragment") fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32
-@stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> f32
-@stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> f32
-@stage("fragment") fn textureSampleCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32
-@stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> f32
-fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32
-fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32
-fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> f32
-fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> f32
-fn textureSampleCompareLevel(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32
-fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> f32
-fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32>
-fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
-fn textureSampleGrad<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32>
-fn textureSampleGrad<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
-fn textureSampleGrad(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
-fn textureSampleGrad(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>, @const offset: vec3<i32>) -> vec4<f32>
-fn textureSampleGrad(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
-fn textureSampleGrad<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
-fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32) -> vec4<f32>
-fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32, @const offset: vec2<i32>) -> vec4<f32>
-fn textureSampleLevel<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, level: f32) -> vec4<f32>
-fn textureSampleLevel<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, level: f32, @const offset: vec2<i32>) -> vec4<f32>
-fn textureSampleLevel(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, level: f32) -> vec4<f32>
-fn textureSampleLevel(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, level: f32, @const offset: vec3<i32>) -> vec4<f32>
-fn textureSampleLevel(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, level: f32) -> vec4<f32>
-fn textureSampleLevel<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, level: f32) -> vec4<f32>
-fn textureSampleLevel<L: iu32>(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, level: L) -> f32
-fn textureSampleLevel<L: iu32>(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, level: L, @const offset: vec2<i32>) -> f32
-fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, level: L) -> f32
-fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, level: L, @const offset: vec2<i32>) -> f32
-fn textureSampleLevel<L: iu32>(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>, level: L) -> f32
-fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_cube_array,sampler: sampler, coords: vec3<f32>, array_index: A, level: L) -> f32
-fn textureSampleBaseClampToEdge(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
-fn textureSampleBaseClampToEdge(texture: texture_external, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_1d<T>) -> u32
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_1d<T>, level: L) -> u32
+@must_use fn textureDimensions<T: fiu32>(texture: texture_2d<T>) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_2d<T>, level: L) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_2d_array<T>) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_2d_array<T>, level: L) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_3d<T>) -> vec3<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_3d<T>, level: L) -> vec3<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_cube<T>) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_cube<T>, level: L) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_cube_array<T>) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_cube_array<T>, level: L) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_multisampled_2d<T>) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_2d) -> vec2<u32>
+@must_use fn textureDimensions<L: iu32>(texture: texture_depth_2d, level: L) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>
+@must_use fn textureDimensions<L: iu32>(texture: texture_depth_2d_array, level: L) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_cube) -> vec2<u32>
+@must_use fn textureDimensions<L: iu32>(texture: texture_depth_cube, level: L) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>
+@must_use fn textureDimensions<L: iu32>(texture: texture_depth_cube_array, level: L) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>
+@must_use fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_1d<F, A>) -> u32
+@must_use fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d<F, A>) -> vec2<u32>
+@must_use fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d_array<F, A>) -> vec2<u32>
+@must_use fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_3d<F, A>) -> vec3<u32>
+@must_use fn textureDimensions(texture: texture_external) -> vec2<u32>
+@must_use fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_cube<T>, sampler: sampler, coords: vec3<f32>) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_cube_array<T>, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<T>
+@must_use fn textureGather(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
+@must_use fn textureGather(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureGather<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<f32>
+@must_use fn textureGather<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureGather(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
+@must_use fn textureGather<A: iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<f32>
+@must_use fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> vec4<f32>
+@must_use fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureGatherCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> vec4<f32>
+@must_use fn textureGatherCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureGatherCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> vec4<f32>
+@must_use fn textureGatherCompare<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> vec4<f32>
+@must_use fn textureNumLayers<T: fiu32>(texture: texture_2d_array<T>) -> u32
+@must_use fn textureNumLayers<T: fiu32>(texture: texture_cube_array<T>) -> u32
+@must_use fn textureNumLayers(texture: texture_depth_2d_array) -> u32
+@must_use fn textureNumLayers(texture: texture_depth_cube_array) -> u32
+@must_use fn textureNumLayers<F: texel_format, A: write>(texture: texture_storage_2d_array<F, A>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_1d<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_2d<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_2d_array<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_3d<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_cube<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_cube_array<T>) -> u32
+@must_use fn textureNumLevels(texture: texture_depth_2d) -> u32
+@must_use fn textureNumLevels(texture: texture_depth_2d_array) -> u32
+@must_use fn textureNumLevels(texture: texture_depth_cube) -> u32
+@must_use fn textureNumLevels(texture: texture_depth_cube_array) -> u32
+@must_use fn textureNumSamples<T: fiu32>(texture: texture_multisampled_2d<T>) -> u32
+@must_use fn textureNumSamples(texture: texture_depth_multisampled_2d) -> u32
+@must_use @stage("fragment") fn textureSample(texture: texture_1d<f32>, sampler: sampler, coords: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, @const offset: vec3<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>) -> f32
+@must_use @stage("fragment") fn textureSample(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> f32
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A) -> f32
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> f32
+@must_use @stage("fragment") fn textureSample(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> f32
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A) -> f32
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, bias: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, bias: f32, @const offset: vec3<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32
+@must_use @stage("fragment") fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32
+@must_use @stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> f32
+@must_use @stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> f32
+@must_use @stage("fragment") fn textureSampleCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32
+@must_use @stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> f32
+@must_use fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32
+@must_use fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32
+@must_use fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> f32
+@must_use fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> f32
+@must_use fn textureSampleCompareLevel(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32
+@must_use fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> f32
+@must_use fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32>
+@must_use fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureSampleGrad<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32>
+@must_use fn textureSampleGrad<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureSampleGrad(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
+@must_use fn textureSampleGrad(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>, @const offset: vec3<i32>) -> vec4<f32>
+@must_use fn textureSampleGrad(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
+@must_use fn textureSampleGrad<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureSampleLevel<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, level: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, level: f32, @const offset: vec3<i32>) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel<L: iu32>(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, level: L) -> f32
+@must_use fn textureSampleLevel<L: iu32>(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, level: L, @const offset: vec2<i32>) -> f32
+@must_use fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, level: L) -> f32
+@must_use fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, level: L, @const offset: vec2<i32>) -> f32
+@must_use fn textureSampleLevel<L: iu32>(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>, level: L) -> f32
+@must_use fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_cube_array,sampler: sampler, coords: vec3<f32>, array_index: A, level: L) -> f32
+@must_use fn textureSampleBaseClampToEdge(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
+@must_use fn textureSampleBaseClampToEdge(texture: texture_external, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
 fn textureStore<C: iu32>(texture: texture_storage_1d<f32_texel_format, write>, coords: C, value: vec4<f32>)
 fn textureStore<C: iu32>(texture: texture_storage_2d<f32_texel_format, write>, coords: vec2<C>, value: vec4<f32>)
 fn textureStore<C: iu32, A: iu32>(texture: texture_storage_2d_array<f32_texel_format, write>, coords: vec2<C>, array_index: A, value: vec4<f32>)
@@ -798,15 +820,15 @@
 fn textureStore<C: iu32>(texture: texture_storage_2d<u32_texel_format, write>, coords: vec2<C>, value: vec4<u32>)
 fn textureStore<C: iu32, A: iu32>(texture: texture_storage_2d_array<u32_texel_format, write>, coords: vec2<C>, array_index: A, value: vec4<u32>)
 fn textureStore(texture: texture_storage_3d<u32_texel_format, write>, coords: vec3<i32>, value: vec4<u32>)
-fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_1d<T>, coords: C, level: L) -> vec4<T>
-fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_2d<T>, coords: vec2<C>, level: L) -> vec4<T>
-fn textureLoad<T: fiu32, C: iu32, A: iu32, L: iu32>(texture: texture_2d_array<T>, coords: vec2<C>, array_index: A, level: L) -> vec4<T>
-fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_3d<T>, coords: vec3<C>, level: L) -> vec4<T>
-fn textureLoad<T: fiu32, C: iu32, S: iu32>(texture: texture_multisampled_2d<T>, coords: vec2<C>, sample_index: S) -> vec4<T>
-fn textureLoad<C: iu32, L: iu32>(texture: texture_depth_2d, coords: vec2<C>, level: L) -> f32
-fn textureLoad<C: iu32, A: iu32, L: iu32>(texture: texture_depth_2d_array, coords: vec2<C>, array_index: A, level: L) -> f32
-fn textureLoad<C: iu32, S: iu32>(texture: texture_depth_multisampled_2d, coords: vec2<C>, sample_index: S) -> f32
-fn textureLoad<C: iu32>(texture: texture_external, coords: vec2<C>) -> vec4<f32>
+@must_use fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_1d<T>, coords: C, level: L) -> vec4<T>
+@must_use fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_2d<T>, coords: vec2<C>, level: L) -> vec4<T>
+@must_use fn textureLoad<T: fiu32, C: iu32, A: iu32, L: iu32>(texture: texture_2d_array<T>, coords: vec2<C>, array_index: A, level: L) -> vec4<T>
+@must_use fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_3d<T>, coords: vec3<C>, level: L) -> vec4<T>
+@must_use fn textureLoad<T: fiu32, C: iu32, S: iu32>(texture: texture_multisampled_2d<T>, coords: vec2<C>, sample_index: S) -> vec4<T>
+@must_use fn textureLoad<C: iu32, L: iu32>(texture: texture_depth_2d, coords: vec2<C>, level: L) -> f32
+@must_use fn textureLoad<C: iu32, A: iu32, L: iu32>(texture: texture_depth_2d_array, coords: vec2<C>, array_index: A, level: L) -> f32
+@must_use fn textureLoad<C: iu32, S: iu32>(texture: texture_depth_multisampled_2d, coords: vec2<C>, sample_index: S) -> f32
+@must_use fn textureLoad<C: iu32>(texture: texture_external, coords: vec2<C>) -> vec4<f32>
 
 @stage("fragment", "compute") fn atomicLoad<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>) -> T
 @stage("fragment", "compute") fn atomicStore<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T)
@@ -821,170 +843,161 @@
 @stage("fragment", "compute") fn atomicCompareExchangeWeak<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T, T) -> __atomic_compare_exchange_result<T>
 
 ////////////////////////////////////////////////////////////////////////////////
-// Type initializers                                                          //
+// Value constructors                                                         //
 ////////////////////////////////////////////////////////////////////////////////
 
-// Zero value initializers
-@const("Zero") init i32() -> i32
-@const("Zero") init u32() -> u32
-@const("Zero") init f32() -> f32
-@const("Zero") init f16() -> f16
-@const("Zero") init bool() -> bool
-@const("Zero") init vec2<T: concrete_scalar>() -> vec2<T>
-@const("Zero") init vec3<T: concrete_scalar>() -> vec3<T>
-@const("Zero") init vec4<T: concrete_scalar>() -> vec4<T>
-@const("Zero") init mat2x2<T: f32_f16>() -> mat2x2<T>
-@const("Zero") init mat2x3<T: f32_f16>() -> mat2x3<T>
-@const("Zero") init mat2x4<T: f32_f16>() -> mat2x4<T>
-@const("Zero") init mat3x2<T: f32_f16>() -> mat3x2<T>
-@const("Zero") init mat3x3<T: f32_f16>() -> mat3x3<T>
-@const("Zero") init mat3x4<T: f32_f16>() -> mat3x4<T>
-@const("Zero") init mat4x2<T: f32_f16>() -> mat4x2<T>
-@const("Zero") init mat4x3<T: f32_f16>() -> mat4x3<T>
-@const("Zero") init mat4x4<T: f32_f16>() -> mat4x4<T>
+// Zero value constructors
+@must_use @const("Zero") ctor i32() -> i32
+@must_use @const("Zero") ctor u32() -> u32
+@must_use @const("Zero") ctor f32() -> f32
+@must_use @const("Zero") ctor f16() -> f16
+@must_use @const("Zero") ctor bool() -> bool
+@must_use @const("Zero") ctor vec2<T: concrete_scalar>() -> vec2<T>
+@must_use @const("Zero") ctor vec3<T: concrete_scalar>() -> vec3<T>
+@must_use @const("Zero") ctor vec4<T: concrete_scalar>() -> vec4<T>
+@must_use @const("Zero") ctor mat2x2<T: f32_f16>() -> mat2x2<T>
+@must_use @const("Zero") ctor mat2x3<T: f32_f16>() -> mat2x3<T>
+@must_use @const("Zero") ctor mat2x4<T: f32_f16>() -> mat2x4<T>
+@must_use @const("Zero") ctor mat3x2<T: f32_f16>() -> mat3x2<T>
+@must_use @const("Zero") ctor mat3x3<T: f32_f16>() -> mat3x3<T>
+@must_use @const("Zero") ctor mat3x4<T: f32_f16>() -> mat3x4<T>
+@must_use @const("Zero") ctor mat4x2<T: f32_f16>() -> mat4x2<T>
+@must_use @const("Zero") ctor mat4x3<T: f32_f16>() -> mat4x3<T>
+@must_use @const("Zero") ctor mat4x4<T: f32_f16>() -> mat4x4<T>
 
-// Identity initializers
-@const("Identity") init i32(i32) -> i32
-@const("Identity") init u32(u32) -> u32
-@const("Identity") init f32(f32) -> f32
-@const("Identity") init f16(f16) -> f16
-@const("Identity") init bool(bool) -> bool
-@const("Identity") init vec2<T: scalar>(vec2<T>) -> vec2<T>
-@const("Identity") init vec3<T: scalar>(vec3<T>) -> vec3<T>
-@const("Identity") init vec4<T: scalar>(vec4<T>) -> vec4<T>
-@const("Identity") init mat2x2<T: f32_f16>(mat2x2<T>) -> mat2x2<T>
-@const("Identity") init mat2x3<T: f32_f16>(mat2x3<T>) -> mat2x3<T>
-@const("Identity") init mat2x4<T: f32_f16>(mat2x4<T>) -> mat2x4<T>
-@const("Identity") init mat3x2<T: f32_f16>(mat3x2<T>) -> mat3x2<T>
-@const("Identity") init mat3x3<T: f32_f16>(mat3x3<T>) -> mat3x3<T>
-@const("Identity") init mat3x4<T: f32_f16>(mat3x4<T>) -> mat3x4<T>
-@const("Identity") init mat4x2<T: f32_f16>(mat4x2<T>) -> mat4x2<T>
-@const("Identity") init mat4x3<T: f32_f16>(mat4x3<T>) -> mat4x3<T>
-@const("Identity") init mat4x4<T: f32_f16>(mat4x4<T>) -> mat4x4<T>
+// Identity constructors
+@must_use @const("Identity") ctor i32(i32) -> i32
+@must_use @const("Identity") ctor u32(u32) -> u32
+@must_use @const("Identity") ctor f32(f32) -> f32
+@must_use @const("Identity") ctor f16(f16) -> f16
+@must_use @const("Identity") ctor bool(bool) -> bool
+@must_use @const("Identity") ctor vec2<T: scalar>(vec2<T>) -> vec2<T>
+@must_use @const("Identity") ctor vec3<T: scalar>(vec3<T>) -> vec3<T>
+@must_use @const("Identity") ctor vec4<T: scalar>(vec4<T>) -> vec4<T>
+@must_use @const("Identity") ctor mat2x2<T: f32_f16>(mat2x2<T>) -> mat2x2<T>
+@must_use @const("Identity") ctor mat2x3<T: f32_f16>(mat2x3<T>) -> mat2x3<T>
+@must_use @const("Identity") ctor mat2x4<T: f32_f16>(mat2x4<T>) -> mat2x4<T>
+@must_use @const("Identity") ctor mat3x2<T: f32_f16>(mat3x2<T>) -> mat3x2<T>
+@must_use @const("Identity") ctor mat3x3<T: f32_f16>(mat3x3<T>) -> mat3x3<T>
+@must_use @const("Identity") ctor mat3x4<T: f32_f16>(mat3x4<T>) -> mat3x4<T>
+@must_use @const("Identity") ctor mat4x2<T: f32_f16>(mat4x2<T>) -> mat4x2<T>
+@must_use @const("Identity") ctor mat4x3<T: f32_f16>(mat4x3<T>) -> mat4x3<T>
+@must_use @const("Identity") ctor mat4x4<T: f32_f16>(mat4x4<T>) -> mat4x4<T>
 
-// Vector initializers (splat)
-@const("VecSplat") init vec2<T: scalar>(T) -> vec2<T>
-@const("VecSplat") init vec3<T: scalar>(T) -> vec3<T>
-@const("VecSplat") init vec4<T: scalar>(T) -> vec4<T>
+// Vector constructors (splat)
+@must_use @const("VecSplat") ctor vec2<T: scalar>(T) -> vec2<T>
+@must_use @const("VecSplat") ctor vec3<T: scalar>(T) -> vec3<T>
+@must_use @const("VecSplat") ctor vec4<T: scalar>(T) -> vec4<T>
 
-// Vector initializers (scalar)
-@const("VecInitS") init vec2<T: scalar>(x: T, y: T) -> vec2<T>
-@const("VecInitS") init vec3<T: scalar>(x: T, y: T, z: T) -> vec3<T>
-@const("VecInitS") init vec4<T: scalar>(x: T, y: T, z: T, w: T) -> vec4<T>
+// Vector constructors (scalar)
+@must_use @const("VecInitS") ctor vec2<T: scalar>(x: T, y: T) -> vec2<T>
+@must_use @const("VecInitS") ctor vec3<T: scalar>(x: T, y: T, z: T) -> vec3<T>
+@must_use @const("VecInitS") ctor vec4<T: scalar>(x: T, y: T, z: T, w: T) -> vec4<T>
 
-// Vector initializers (mixed)
-@const("VecInitM") init vec3<T: scalar>(xy: vec2<T>, z: T) -> vec3<T>
-@const("VecInitM") init vec3<T: scalar>(x: T, yz: vec2<T>) -> vec3<T>
-@const("VecInitM") init vec4<T: scalar>(xy: vec2<T>, z: T, w: T) -> vec4<T>
-@const("VecInitM") init vec4<T: scalar>(x: T, yz: vec2<T>, w: T) -> vec4<T>
-@const("VecInitM") init vec4<T: scalar>(x: T, y: T, zw: vec2<T>) -> vec4<T>
-@const("VecInitM") init vec4<T: scalar>(xy: vec2<T>, zw: vec2<T>) -> vec4<T>
-@const("VecInitM") init vec4<T: scalar>(xyz: vec3<T>, w: T) -> vec4<T>
-@const("VecInitM") init vec4<T: scalar>(x: T, zyw: vec3<T>) -> vec4<T>
+// Vector constructors (mixed)
+@must_use @const("VecInitM") ctor vec3<T: scalar>(xy: vec2<T>, z: T) -> vec3<T>
+@must_use @const("VecInitM") ctor vec3<T: scalar>(x: T, yz: vec2<T>) -> vec3<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(xy: vec2<T>, z: T, w: T) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(x: T, yz: vec2<T>, w: T) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(x: T, y: T, zw: vec2<T>) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(xy: vec2<T>, zw: vec2<T>) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(xyz: vec3<T>, w: T) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(x: T, zyw: vec3<T>) -> vec4<T>
 
-// Matrix initializers (scalar)
-@const("MatInitS")
-init mat2x2<T: fa_f32_f16>(T, T,
+// Matrix constructors (scalar)
+@must_use @const("MatInitS")
+ctor mat2x2<T: fa_f32_f16>(T, T,
                            T, T) -> mat2x2<T>
-@const("MatInitS")
-init mat2x3<T: fa_f32_f16>(T, T, T,
+@must_use @const("MatInitS")
+ctor mat2x3<T: fa_f32_f16>(T, T, T,
                            T, T, T) -> mat2x3<T>
-@const("MatInitS")
-init mat2x4<T: fa_f32_f16>(T, T, T, T,
+@must_use @const("MatInitS")
+ctor mat2x4<T: fa_f32_f16>(T, T, T, T,
                            T, T, T, T) -> mat2x4<T>
-@const("MatInitS")
-init mat3x2<T: fa_f32_f16>(T, T,
+@must_use @const("MatInitS")
+ctor mat3x2<T: fa_f32_f16>(T, T,
                            T, T,
                            T, T) -> mat3x2<T>
-@const("MatInitS")
-init mat3x3<T: fa_f32_f16>(T, T, T,
+@must_use @const("MatInitS")
+ctor mat3x3<T: fa_f32_f16>(T, T, T,
                            T, T, T,
                            T, T, T) -> mat3x3<T>
-@const("MatInitS")
-init mat3x4<T: fa_f32_f16>(T, T, T, T,
+@must_use @const("MatInitS")
+ctor mat3x4<T: fa_f32_f16>(T, T, T, T,
                            T, T, T, T,
                            T, T, T, T) -> mat3x4<T>
-@const("MatInitS")
-init mat4x2<T: fa_f32_f16>(T, T,
+@must_use @const("MatInitS")
+ctor mat4x2<T: fa_f32_f16>(T, T,
                            T, T,
                            T, T,
                            T, T) -> mat4x2<T>
-@const("MatInitS")
-init mat4x3<T: fa_f32_f16>(T, T, T,
+@must_use @const("MatInitS")
+ctor mat4x3<T: fa_f32_f16>(T, T, T,
                            T, T, T,
                            T, T, T,
                            T, T, T) -> mat4x3<T>
-@const("MatInitS")
-init mat4x4<T: fa_f32_f16>(T, T, T, T,
+@must_use @const("MatInitS")
+ctor mat4x4<T: fa_f32_f16>(T, T, T, T,
                            T, T, T, T,
                            T, T, T, T,
                            T, T, T, T) -> mat4x4<T>
 
-// Matrix initializers (column vectors)
-@const("MatInitV")
-init mat2x2<T: fa_f32_f16>(vec2<T>, vec2<T>) -> mat2x2<T>
-@const("MatInitV")
-init mat2x3<T: fa_f32_f16>(vec3<T>, vec3<T>) -> mat2x3<T>
-@const("MatInitV")
-init mat2x4<T: fa_f32_f16>(vec4<T>, vec4<T>) -> mat2x4<T>
-@const("MatInitV")
-init mat3x2<T: fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T>
-@const("MatInitV")
-init mat3x3<T: fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T>
-@const("MatInitV")
-init mat3x4<T: fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T>
-@const("MatInitV")
-init mat4x2<T: fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T>
-@const("MatInitV")
-init mat4x3<T: fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T>
-@const("MatInitV")
-init mat4x4<T: fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T>
+// Matrix constructors (column vectors)
+@must_use @const("MatInitV") ctor mat2x2<T: fa_f32_f16>(vec2<T>, vec2<T>) -> mat2x2<T>
+@must_use @const("MatInitV") ctor mat2x3<T: fa_f32_f16>(vec3<T>, vec3<T>) -> mat2x3<T>
+@must_use @const("MatInitV") ctor mat2x4<T: fa_f32_f16>(vec4<T>, vec4<T>) -> mat2x4<T>
+@must_use @const("MatInitV") ctor mat3x2<T: fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T>
+@must_use @const("MatInitV") ctor mat3x3<T: fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T>
+@must_use @const("MatInitV") ctor mat3x4<T: fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T>
+@must_use @const("MatInitV") ctor mat4x2<T: fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T>
+@must_use @const("MatInitV") ctor mat4x3<T: fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T>
+@must_use @const("MatInitV") ctor mat4x4<T: fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T>
 
 ////////////////////////////////////////////////////////////////////////////////
-// Type conversions                                                           //
+// Value conversions                                                          //
 ////////////////////////////////////////////////////////////////////////////////
-@const conv f32<T: scalar_no_f32>(T) -> f32
-@const conv f16<T: scalar_no_f16>(T) -> f16
-@const conv i32<T: scalar_no_i32>(T) -> i32
-@const conv u32<T: scalar_no_u32>(T) -> u32
-@const conv bool<T: scalar_no_bool>(T) -> bool
+@must_use @const conv f32<T: scalar_no_f32>(T) -> f32
+@must_use @const conv f16<T: scalar_no_f16>(T) -> f16
+@must_use @const conv i32<T: scalar_no_i32>(T) -> i32
+@must_use @const conv u32<T: scalar_no_u32>(T) -> u32
+@must_use @const conv bool<T: scalar_no_bool>(T) -> bool
 
-@const conv vec2<T: f32, U: scalar_no_f32>(vec2<U>) -> vec2<f32>
-@const conv vec2<T: f16, U: scalar_no_f16>(vec2<U>) -> vec2<f16>
-@const conv vec2<T: i32, U: scalar_no_i32>(vec2<U>) -> vec2<i32>
-@const conv vec2<T: u32, U: scalar_no_u32>(vec2<U>) -> vec2<u32>
-@const conv vec2<T: bool, U: scalar_no_bool>(vec2<U>) -> vec2<bool>
+@must_use @const conv vec2<T: f32, U: scalar_no_f32>(vec2<U>) -> vec2<f32>
+@must_use @const conv vec2<T: f16, U: scalar_no_f16>(vec2<U>) -> vec2<f16>
+@must_use @const conv vec2<T: i32, U: scalar_no_i32>(vec2<U>) -> vec2<i32>
+@must_use @const conv vec2<T: u32, U: scalar_no_u32>(vec2<U>) -> vec2<u32>
+@must_use @const conv vec2<T: bool, U: scalar_no_bool>(vec2<U>) -> vec2<bool>
 
-@const conv vec3<T: f32, U: scalar_no_f32>(vec3<U>) -> vec3<f32>
-@const conv vec3<T: f16, U: scalar_no_f16>(vec3<U>) -> vec3<f16>
-@const conv vec3<T: i32, U: scalar_no_i32>(vec3<U>) -> vec3<i32>
-@const conv vec3<T: u32, U: scalar_no_u32>(vec3<U>) -> vec3<u32>
-@const conv vec3<T: bool, U: scalar_no_bool>(vec3<U>) -> vec3<bool>
+@must_use @const conv vec3<T: f32, U: scalar_no_f32>(vec3<U>) -> vec3<f32>
+@must_use @const conv vec3<T: f16, U: scalar_no_f16>(vec3<U>) -> vec3<f16>
+@must_use @const conv vec3<T: i32, U: scalar_no_i32>(vec3<U>) -> vec3<i32>
+@must_use @const conv vec3<T: u32, U: scalar_no_u32>(vec3<U>) -> vec3<u32>
+@must_use @const conv vec3<T: bool, U: scalar_no_bool>(vec3<U>) -> vec3<bool>
 
-@const conv vec4<T: f32, U: scalar_no_f32>(vec4<U>) -> vec4<f32>
-@const conv vec4<T: f16, U: scalar_no_f16>(vec4<U>) -> vec4<f16>
-@const conv vec4<T: i32, U: scalar_no_i32>(vec4<U>) -> vec4<i32>
-@const conv vec4<T: u32, U: scalar_no_u32>(vec4<U>) -> vec4<u32>
-@const conv vec4<T: bool, U: scalar_no_bool>(vec4<U>) -> vec4<bool>
+@must_use @const conv vec4<T: f32, U: scalar_no_f32>(vec4<U>) -> vec4<f32>
+@must_use @const conv vec4<T: f16, U: scalar_no_f16>(vec4<U>) -> vec4<f16>
+@must_use @const conv vec4<T: i32, U: scalar_no_i32>(vec4<U>) -> vec4<i32>
+@must_use @const conv vec4<T: u32, U: scalar_no_u32>(vec4<U>) -> vec4<u32>
+@must_use @const conv vec4<T: bool, U: scalar_no_bool>(vec4<U>) -> vec4<bool>
 
-@const conv mat2x2<T: f16>(mat2x2<f32>) -> mat2x2<f16>
-@const conv mat2x2<T: f32>(mat2x2<f16>) -> mat2x2<f32>
-@const conv mat2x3<T: f16>(mat2x3<f32>) -> mat2x3<f16>
-@const conv mat2x3<T: f32>(mat2x3<f16>) -> mat2x3<f32>
-@const conv mat2x4<T: f16>(mat2x4<f32>) -> mat2x4<f16>
-@const conv mat2x4<T: f32>(mat2x4<f16>) -> mat2x4<f32>
-@const conv mat3x2<T: f16>(mat3x2<f32>) -> mat3x2<f16>
-@const conv mat3x2<T: f32>(mat3x2<f16>) -> mat3x2<f32>
-@const conv mat3x3<T: f16>(mat3x3<f32>) -> mat3x3<f16>
-@const conv mat3x3<T: f32>(mat3x3<f16>) -> mat3x3<f32>
-@const conv mat3x4<T: f16>(mat3x4<f32>) -> mat3x4<f16>
-@const conv mat3x4<T: f32>(mat3x4<f16>) -> mat3x4<f32>
-@const conv mat4x2<T: f16>(mat4x2<f32>) -> mat4x2<f16>
-@const conv mat4x2<T: f32>(mat4x2<f16>) -> mat4x2<f32>
-@const conv mat4x3<T: f16>(mat4x3<f32>) -> mat4x3<f16>
-@const conv mat4x3<T: f32>(mat4x3<f16>) -> mat4x3<f32>
-@const conv mat4x4<T: f16>(mat4x4<f32>) -> mat4x4<f16>
-@const conv mat4x4<T: f32>(mat4x4<f16>) -> mat4x4<f32>
+@must_use @const conv mat2x2<T: f16>(mat2x2<f32>) -> mat2x2<f16>
+@must_use @const conv mat2x2<T: f32>(mat2x2<f16>) -> mat2x2<f32>
+@must_use @const conv mat2x3<T: f16>(mat2x3<f32>) -> mat2x3<f16>
+@must_use @const conv mat2x3<T: f32>(mat2x3<f16>) -> mat2x3<f32>
+@must_use @const conv mat2x4<T: f16>(mat2x4<f32>) -> mat2x4<f16>
+@must_use @const conv mat2x4<T: f32>(mat2x4<f16>) -> mat2x4<f32>
+@must_use @const conv mat3x2<T: f16>(mat3x2<f32>) -> mat3x2<f16>
+@must_use @const conv mat3x2<T: f32>(mat3x2<f16>) -> mat3x2<f32>
+@must_use @const conv mat3x3<T: f16>(mat3x3<f32>) -> mat3x3<f16>
+@must_use @const conv mat3x3<T: f32>(mat3x3<f16>) -> mat3x3<f32>
+@must_use @const conv mat3x4<T: f16>(mat3x4<f32>) -> mat3x4<f16>
+@must_use @const conv mat3x4<T: f32>(mat3x4<f16>) -> mat3x4<f32>
+@must_use @const conv mat4x2<T: f16>(mat4x2<f32>) -> mat4x2<f16>
+@must_use @const conv mat4x2<T: f32>(mat4x2<f16>) -> mat4x2<f32>
+@must_use @const conv mat4x3<T: f16>(mat4x3<f32>) -> mat4x3<f16>
+@must_use @const conv mat4x3<T: f32>(mat4x3<f16>) -> mat4x3<f32>
+@must_use @const conv mat4x4<T: f16>(mat4x4<f32>) -> mat4x4<f16>
+@must_use @const conv mat4x4<T: f32>(mat4x4<f16>) -> mat4x4<f32>
 
 ////////////////////////////////////////////////////////////////////////////////
 // Operators                                                                  //
@@ -1002,89 +1015,89 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Unary Operators                                                            //
 ////////////////////////////////////////////////////////////////////////////////
-@const op ! (bool) -> bool
-@const op ! <N: num> (vec<N, bool>) -> vec<N, bool>
+@must_use @const op ! (bool) -> bool
+@must_use @const op ! <N: num> (vec<N, bool>) -> vec<N, bool>
 
-@const op ~ <T: ia_iu32>(T) -> T
-@const op ~ <T: ia_iu32, N: num> (vec<N, T>) -> vec<N, T>
+@must_use @const op ~ <T: ia_iu32>(T) -> T
+@must_use @const op ~ <T: ia_iu32, N: num> (vec<N, T>) -> vec<N, T>
 
-@const("UnaryMinus") op - <T: fia_fi32_f16>(T) -> T
-@const("UnaryMinus") op - <T: fia_fi32_f16, N: num> (vec<N, T>) -> vec<N, T>
+@must_use @const("UnaryMinus") op - <T: fia_fi32_f16>(T) -> T
+@must_use @const("UnaryMinus") op - <T: fia_fi32_f16, N: num> (vec<N, T>) -> vec<N, T>
 
 ////////////////////////////////////////////////////////////////////////////////
 // Binary Operators                                                           //
 ////////////////////////////////////////////////////////////////////////////////
-@const op + <T: fia_fiu32_f16>(T, T) -> T
-@const op + <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-@const op + <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
-@const op + <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
-@const op + <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T>
+@must_use @const op + <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const op + <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op + <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const op + <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@must_use @const op + <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T>
 
-@const op - <T: fia_fiu32_f16>(T, T) -> T
-@const op - <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-@const op - <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
-@const op - <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
-@const op - <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T>
+@must_use @const op - <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const op - <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op - <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const op - <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@must_use @const op - <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T>
 
-@const("Multiply") op * <T: fia_fiu32_f16>(T, T) -> T
-@const("Multiply") op * <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-@const("Multiply") op * <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
-@const("Multiply") op * <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
-@const("Multiply") op * <T: fa_f32_f16, N: num, M: num> (T, mat<N, M, T>) -> mat<N, M, T>
-@const("Multiply") op * <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, T) -> mat<N, M, T>
-@const("MultiplyMatVec") op * <T: fa_f32_f16, C: num, R: num> (mat<C, R, T>, vec<C, T>) -> vec<R, T>
-@const("MultiplyVecMat") op * <T: fa_f32_f16, C: num, R: num> (vec<R, T>, mat<C, R, T>) -> vec<C, T>
-@const("MultiplyMatMat") op * <T: fa_f32_f16, K: num, C: num, R: num> (mat<K, R, T>, mat<C, K, T>) -> mat<C, R, T>
+@must_use @const("Multiply") op * <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const("Multiply") op * <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const("Multiply") op * <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const("Multiply") op * <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@must_use @const("Multiply") op * <T: fa_f32_f16, N: num, M: num> (T, mat<N, M, T>) -> mat<N, M, T>
+@must_use @const("Multiply") op * <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, T) -> mat<N, M, T>
+@must_use @const("MultiplyMatVec") op * <T: fa_f32_f16, C: num, R: num> (mat<C, R, T>, vec<C, T>) -> vec<R, T>
+@must_use @const("MultiplyVecMat") op * <T: fa_f32_f16, C: num, R: num> (vec<R, T>, mat<C, R, T>) -> vec<C, T>
+@must_use @const("MultiplyMatMat") op * <T: fa_f32_f16, K: num, C: num, R: num> (mat<K, R, T>, mat<C, K, T>) -> mat<C, R, T>
 
-@const op / <T: fia_fiu32_f16>(T, T) -> T
-@const op / <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-@const op / <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
-@const op / <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@must_use @const op / <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const op / <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op / <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const op / <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
 
-@const op % <T: fia_fiu32_f16>(T, T) -> T
-@const op % <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
-@const op % <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
-@const op % <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@must_use @const op % <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const op % <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op % <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const op % <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
 
-@const op ^ <T: ia_iu32>(T, T) -> T
-@const op ^ <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op ^ <T: ia_iu32>(T, T) -> T
+@must_use @const op ^ <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
 
-@const op & (bool, bool) -> bool
-@const op & <N: num> (vec<N, bool>, vec<N, bool>) -> vec<N, bool>
-@const op & <T: ia_iu32>(T, T) -> T
-@const op & <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op & (bool, bool) -> bool
+@must_use @const op & <N: num> (vec<N, bool>, vec<N, bool>) -> vec<N, bool>
+@must_use @const op & <T: ia_iu32>(T, T) -> T
+@must_use @const op & <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
 
-@const op | (bool, bool) -> bool
-@const op | <N: num> (vec<N, bool>, vec<N, bool>) -> vec<N, bool>
-@const op | <T: ia_iu32>(T, T) -> T
-@const op | <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op | (bool, bool) -> bool
+@must_use @const op | <N: num> (vec<N, bool>, vec<N, bool>) -> vec<N, bool>
+@must_use @const op | <T: ia_iu32>(T, T) -> T
+@must_use @const op | <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
 
-@const op && (bool, bool) -> bool
-@const op || (bool, bool) -> bool
+@must_use @const op && (bool, bool) -> bool
+@must_use @const op || (bool, bool) -> bool
 
-@const op == <T: scalar>(T, T) -> bool
-@const op == <T: scalar, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+@must_use @const op == <T: scalar>(T, T) -> bool
+@must_use @const op == <T: scalar, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
 
-@const op != <T: scalar>(T, T) -> bool
-@const op != <T: scalar, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+@must_use @const op != <T: scalar>(T, T) -> bool
+@must_use @const op != <T: scalar, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
 
-@const op < <T: fia_fiu32_f16>(T, T) -> bool
-@const op < <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+@must_use @const op < <T: fia_fiu32_f16>(T, T) -> bool
+@must_use @const op < <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
 
-@const op > <T: fia_fiu32_f16>(T, T) -> bool
-@const op > <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+@must_use @const op > <T: fia_fiu32_f16>(T, T) -> bool
+@must_use @const op > <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
 
-@const op <= <T: fia_fiu32_f16>(T, T) -> bool
-@const op <= <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+@must_use @const op <= <T: fia_fiu32_f16>(T, T) -> bool
+@must_use @const op <= <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
 
-@const op >= <T: fia_fiu32_f16>(T, T) -> bool
-@const op >= <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+@must_use @const op >= <T: fia_fiu32_f16>(T, T) -> bool
+@must_use @const op >= <T: fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
 
-@const op << <T: ia_iu32>(T, u32) -> T
-@const op << <T: ia_iu32, N: num> (vec<N, T>, vec<N, u32>) -> vec<N, T>
+@must_use @const op << <T: ia_iu32>(T, u32) -> T
+@must_use @const op << <T: ia_iu32, N: num> (vec<N, T>, vec<N, u32>) -> vec<N, T>
 
-@const op >> <T: ia_iu32>(T, u32) -> T
-@const op >> <T: ia_iu32, N: num> (vec<N, T>, vec<N, u32>) -> vec<N, T>
+@must_use @const op >> <T: ia_iu32>(T, u32) -> T
+@must_use @const op >> <T: ia_iu32, N: num> (vec<N, T>, vec<N, u32>) -> vec<N, T>
 
 ////////////////////////////////////////////////////////////////////////////////
 // Tint internal builtins                                                     //
diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc
index cbc7165..d3f8d53 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -800,6 +800,9 @@
         // [&](const ast::InvariantAttribute* i) {
         // TODO(dsinclair): Implement
         // },
+        // [&](const ast::MustUseAttribute* i) {
+        // TODO(dsinclair): Implement
+        // },
         [&](const ast::IdAttribute*) {
             diagnostics_.add_warning(tint::diag::System::IR,
                                      "found an `Id` attribute. The SubstituteOverrides transform "
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index 6430c58..ccf0ccf 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -1468,7 +1468,7 @@
 
 TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_True) {
     auto* expr = Expr(true);
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate, expr);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate, expr);
 
     auto& b = CreateBuilder();
     auto r = b.EmitLiteral(expr);
@@ -1482,7 +1482,7 @@
 
 TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_False) {
     auto* expr = Expr(false);
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate, expr);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate, expr);
 
     auto& b = CreateBuilder();
     auto r = b.EmitLiteral(expr);
@@ -1496,7 +1496,7 @@
 
 TEST_F(IR_BuilderImplTest, EmitLiteral_F32) {
     auto* expr = Expr(1.2_f);
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate, expr);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate, expr);
 
     auto& b = CreateBuilder();
     auto r = b.EmitLiteral(expr);
@@ -1511,7 +1511,7 @@
 TEST_F(IR_BuilderImplTest, EmitLiteral_F16) {
     Enable(builtin::Extension::kF16);
     auto* expr = Expr(1.2_h);
-    GlobalVar("a", ty.f16(), type::AddressSpace::kPrivate, expr);
+    GlobalVar("a", ty.f16(), builtin::AddressSpace::kPrivate, expr);
 
     auto& b = CreateBuilder();
     auto r = b.EmitLiteral(expr);
@@ -1525,7 +1525,7 @@
 
 TEST_F(IR_BuilderImplTest, EmitLiteral_I32) {
     auto* expr = Expr(-2_i);
-    GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate, expr);
+    GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate, expr);
 
     auto& b = CreateBuilder();
     auto r = b.EmitLiteral(expr);
@@ -1539,7 +1539,7 @@
 
 TEST_F(IR_BuilderImplTest, EmitLiteral_U32) {
     auto* expr = Expr(2_u);
-    GlobalVar("a", ty.u32(), type::AddressSpace::kPrivate, expr);
+    GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate, expr);
 
     auto& b = CreateBuilder();
     auto r = b.EmitLiteral(expr);
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 0f8a6ed..c84a6e0 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -56,6 +56,7 @@
 #include "src/tint/ast/loop_statement.h"
 #include "src/tint/ast/member_accessor_expression.h"
 #include "src/tint/ast/module.h"
+#include "src/tint/ast/must_use_attribute.h"
 #include "src/tint/ast/override.h"
 #include "src/tint/ast/parameter.h"
 #include "src/tint/ast/phony_expression.h"
@@ -74,6 +75,8 @@
 #include "src/tint/ast/while_statement.h"
 #include "src/tint/ast/workgroup_attribute.h"
 #include "src/tint/builtin/extension.h"
+#include "src/tint/builtin/interpolation_sampling.h"
+#include "src/tint/builtin/interpolation_type.h"
 #include "src/tint/constant/composite.h"
 #include "src/tint/constant/splat.h"
 #include "src/tint/constant/value.h"
@@ -219,24 +222,34 @@
     /// constructing an ast::Var.
     struct VarOptions {
         template <typename... ARGS>
-        explicit VarOptions(ARGS&&... args) {
-            (Set(std::forward<ARGS>(args)), ...);
+        explicit VarOptions(ProgramBuilder& b, ARGS&&... args) {
+            (Set(b, std::forward<ARGS>(args)), ...);
         }
         ~VarOptions();
 
         ast::Type type;
-        type::AddressSpace address_space = type::AddressSpace::kNone;
-        type::Access access = type::Access::kUndefined;
+        const ast::Expression* address_space = nullptr;
+        const ast::Expression* access = nullptr;
         const ast::Expression* initializer = nullptr;
         utils::Vector<const ast::Attribute*, 4> attributes;
 
       private:
-        void Set(ast::Type t) { type = t; }
-        void Set(type::AddressSpace addr_space) { address_space = addr_space; }
-        void Set(type::Access ac) { access = ac; }
-        void Set(const ast::Expression* c) { initializer = c; }
-        void Set(utils::VectorRef<const ast::Attribute*> l) { attributes = std::move(l); }
-        void Set(const ast::Attribute* a) { attributes.Push(a); }
+        void Set(ProgramBuilder&, ast::Type t) { type = t; }
+        void Set(ProgramBuilder& b, builtin::AddressSpace addr_space) {
+            if (addr_space != builtin::AddressSpace::kUndefined) {
+                address_space = b.Expr(addr_space);
+            }
+        }
+        void Set(ProgramBuilder& b, builtin::Access ac) {
+            if (ac != builtin::Access::kUndefined) {
+                access = b.Expr(ac);
+            }
+        }
+        void Set(ProgramBuilder&, const ast::Expression* c) { initializer = c; }
+        void Set(ProgramBuilder&, utils::VectorRef<const ast::Attribute*> l) {
+            attributes = std::move(l);
+        }
+        void Set(ProgramBuilder&, const ast::Attribute* a) { attributes.Push(a); }
     };
 
     /// LetOptions is a helper for accepting an arbitrary number of order independent options for
@@ -460,7 +473,7 @@
     /// Creates a new ast::Node owned by the ProgramBuilder. When the
     /// ProgramBuilder is destructed, the ast::Node will also be destructed.
     /// @param source the Source of the node
-    /// @param args the arguments to pass to the type constructor
+    /// @param args the arguments to pass to the constructor
     /// @returns the node pointer
     template <typename T, typename... ARGS>
     traits::EnableIfIsType<T, ast::Node>* create(const Source& source, ARGS&&... args) {
@@ -485,8 +498,8 @@
     /// constructor.
     /// When the ProgramBuilder is destructed, the ast::Node will also be
     /// destructed.
-    /// @param arg0 the first arguments to pass to the type constructor
-    /// @param args the remaining arguments to pass to the type constructor
+    /// @param arg0 the first arguments to pass to the constructor
+    /// @param args the remaining arguments to pass to the constructor
     /// @returns the node pointer
     template <typename T, typename ARG0, typename... ARGS>
     traits::EnableIf</* T is ast::Node and ARG0 is not Source */
@@ -1189,10 +1202,10 @@
         /// @param type the type of the pointer
         /// @param address_space the address space of the pointer
         /// @param access the optional access control of the pointer
-        /// @return the pointer to `type` with the given type::AddressSpace
+        /// @return the pointer to `type` with the given builtin::AddressSpace
         ast::Type pointer(ast::Type type,
-                          type::AddressSpace address_space,
-                          type::Access access = type::Access::kUndefined) const {
+                          builtin::AddressSpace address_space,
+                          builtin::Access access = builtin::Access::kUndefined) const {
             return pointer(builder->source_, type, address_space, access);
         }
 
@@ -1200,12 +1213,12 @@
         /// @param type the type of the pointer
         /// @param address_space the address space of the pointer
         /// @param access the optional access control of the pointer
-        /// @return the pointer to `type` with the given type::AddressSpace
+        /// @return the pointer to `type` with the given builtin::AddressSpace
         ast::Type pointer(const Source& source,
                           ast::Type type,
-                          type::AddressSpace address_space,
-                          type::Access access = type::Access::kUndefined) const {
-            if (access != type::Access::kUndefined) {
+                          builtin::AddressSpace address_space,
+                          builtin::Access access = builtin::Access::kUndefined) const {
+            if (access != builtin::Access::kUndefined) {
                 return (*this)(source, "ptr", address_space, type, access);
             } else {
                 return (*this)(source, "ptr", address_space, type);
@@ -1214,22 +1227,22 @@
 
         /// @param address_space the address space of the pointer
         /// @param access the optional access control of the pointer
-        /// @return the pointer to type `T` with the given type::AddressSpace.
+        /// @return the pointer to type `T` with the given builtin::AddressSpace.
         template <typename T>
-        ast::Type pointer(type::AddressSpace address_space,
-                          type::Access access = type::Access::kUndefined) const {
+        ast::Type pointer(builtin::AddressSpace address_space,
+                          builtin::Access access = builtin::Access::kUndefined) const {
             return pointer<T>(builder->source_, address_space, access);
         }
 
         /// @param source the Source of the node
         /// @param address_space the address space of the pointer
         /// @param access the optional access control of the pointer
-        /// @return the pointer to type `T` with the given type::AddressSpace.
+        /// @return the pointer to type `T` with the given builtin::AddressSpace.
         template <typename T>
         ast::Type pointer(const Source& source,
-                          type::AddressSpace address_space,
-                          type::Access access = type::Access::kUndefined) const {
-            if (access != type::Access::kUndefined) {
+                          builtin::AddressSpace address_space,
+                          builtin::Access access = builtin::Access::kUndefined) const {
+            if (access != builtin::Access::kUndefined) {
                 return (*this)(source, "ptr", address_space, Of<T>(), access);
             } else {
                 return (*this)(source, "ptr", address_space, Of<T>());
@@ -1379,8 +1392,8 @@
         /// @param access the access control of the texture
         /// @returns the storage texture
         ast::Type storage_texture(type::TextureDimension dims,
-                                  type::TexelFormat format,
-                                  type::Access access) const {
+                                  builtin::TexelFormat format,
+                                  builtin::Access access) const {
             return storage_texture(builder->source_, dims, format, access);
         }
 
@@ -1391,8 +1404,8 @@
         /// @returns the storage texture
         ast::Type storage_texture(const Source& source,
                                   type::TextureDimension dims,
-                                  type::TexelFormat format,
-                                  type::Access access) const {
+                                  builtin::TexelFormat format,
+                                  builtin::Access access) const {
             switch (dims) {
                 case type::TextureDimension::k1d:
                     return (*this)(source, "texture_storage_1d", format, access);
@@ -1483,23 +1496,24 @@
 
     /// @param identifier the identifier symbol
     /// @param args the templated identifier arguments
-    /// @return an ast::TemplatedIdentifier with the given symbol and template arguments
+    /// @return an ast::Identifier with the given symbol and template arguments
     template <typename IDENTIFIER, typename... ARGS, typename = DisableIfSource<IDENTIFIER>>
-    const ast::TemplatedIdentifier* Ident(IDENTIFIER&& identifier, ARGS&&... args) {
+    const ast::Identifier* Ident(IDENTIFIER&& identifier, ARGS&&... args) {
         return Ident(source_, std::forward<IDENTIFIER>(identifier), std::forward<ARGS>(args)...);
     }
 
     /// @param source the source information
     /// @param identifier the identifier symbol
     /// @param args the templated identifier arguments
-    /// @return an ast::TemplatedIdentifier with the given symbol and template arguments
+    /// @return an ast::Identifier with the given symbol and template arguments
     template <typename IDENTIFIER, typename... ARGS>
-    const ast::TemplatedIdentifier* Ident(const Source& source,
-                                          IDENTIFIER&& identifier,
-                                          ARGS&&... args) {
+    const ast::Identifier* Ident(const Source& source, IDENTIFIER&& identifier, ARGS&&... args) {
+        auto arg_exprs = ExprList(std::forward<ARGS>(args)...);
+        if (arg_exprs.IsEmpty()) {
+            return create<ast::Identifier>(source, Sym(std::forward<IDENTIFIER>(identifier)));
+        }
         return create<ast::TemplatedIdentifier>(source, Sym(std::forward<IDENTIFIER>(identifier)),
-                                                ExprList(std::forward<ARGS>(args)...),
-                                                utils::Empty);
+                                                std::move(arg_exprs), utils::Empty);
     }
 
     /// @param expr the expression
@@ -1692,7 +1706,7 @@
 
     /// @param type the vector type
     /// @param size the vector size
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a `size`-element vector of
     /// type `type`, constructed with the values @p args.
     template <typename... ARGS>
@@ -1703,7 +1717,7 @@
     /// @param source the source of the call
     /// @param type the vector type
     /// @param size the vector size
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a `size`-element vector of
     /// type `type`, constructed with the values @p args.
     template <typename... ARGS>
@@ -1714,7 +1728,7 @@
         return Call(source, ty.vec(type, size), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 2-element vector of type `T`, constructed with the
     /// values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1723,7 +1737,7 @@
     }
 
     /// @param source the vector source
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 2-element vector of type `T`, constructed with the
     /// values @p args.
     template <typename T, typename... ARGS>
@@ -1732,7 +1746,7 @@
     }
 
     /// @param type the element type of the vector
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 2-element vector of type @p type, constructed with the
     /// values @p args.
     template <typename... ARGS>
@@ -1742,7 +1756,7 @@
 
     /// @param source the vector source
     /// @param type the element type of the vector
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 2-element vector of type @p type, constructed with the
     /// values @p args.
     template <typename... ARGS>
@@ -1750,7 +1764,7 @@
         return Call(source, ty.vec2(type), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 3-element vector of type `T`, constructed with the
     /// values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1759,7 +1773,7 @@
     }
 
     /// @param source the vector source
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 3-element vector of type `T`, constructed with the
     /// values @p args.
     template <typename T, typename... ARGS>
@@ -1768,7 +1782,7 @@
     }
 
     /// @param type the element type of the vector
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 3-element vector of type @p type, constructed with the
     /// values @p args.
     template <typename... ARGS>
@@ -1778,7 +1792,7 @@
 
     /// @param source the vector source
     /// @param type the element type of the vector
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 3-element vector of type @p type, constructed with the
     /// values @p args.
     template <typename... ARGS>
@@ -1786,7 +1800,7 @@
         return Call(source, ty.vec3(type), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 4-element vector of type `T`, constructed with the
     /// values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1795,7 +1809,7 @@
     }
 
     /// @param source the vector source
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 4-element vector of type `T`, constructed with the
     /// values @p args.
     template <typename T, typename... ARGS>
@@ -1804,7 +1818,7 @@
     }
 
     /// @param type the element type of the vector
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 4-element vector of type @p type, constructed with the
     /// values @p args.
     template <typename... ARGS>
@@ -1814,7 +1828,7 @@
 
     /// @param source the vector source
     /// @param type the element type of the vector
-    /// @param args the arguments for the vector initializer
+    /// @param args the arguments for the vector constructor
     /// @return an `ast::CallExpression` of a 4-element vector of type @p type, constructed with the
     /// values @p args.
     template <typename... ARGS>
@@ -1822,7 +1836,7 @@
         return Call(source, ty.vec4(type), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 2x2 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1831,7 +1845,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 2x2 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1839,7 +1853,7 @@
         return Call(source, ty.mat2x2<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 2x3 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1848,7 +1862,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 2x3 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1856,7 +1870,7 @@
         return Call(source, ty.mat2x3<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 2x4 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1865,7 +1879,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 2x4 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1873,7 +1887,7 @@
         return Call(source, ty.mat2x4<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 3x2 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1882,7 +1896,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 3x2 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1890,7 +1904,7 @@
         return Call(source, ty.mat3x2<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 3x3 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1899,7 +1913,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 3x3 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1907,7 +1921,7 @@
         return Call(source, ty.mat3x3<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 3x4 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1916,7 +1930,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 3x4 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1924,7 +1938,7 @@
         return Call(source, ty.mat3x4<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 4x2 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1933,7 +1947,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 4x2 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1941,7 +1955,7 @@
         return Call(source, ty.mat4x2<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 4x3 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1950,7 +1964,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 4x3 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1958,7 +1972,7 @@
         return Call(source, ty.mat4x3<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 4x4 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1967,7 +1981,7 @@
     }
 
     /// @param source the matrix source
-    /// @param args the arguments for the matrix initializer
+    /// @param args the arguments for the matrix constructor
     /// @return an `ast::CallExpression` of a 4x4 matrix of type
     /// `T`, constructed with the values @p args.
     template <typename T, typename... ARGS>
@@ -1975,7 +1989,7 @@
         return Call(source, ty.mat4x4<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the array initializer
+    /// @param args the arguments for the array constructor
     /// @return an `ast::CallExpression` of an array with element type `T`, constructed with the
     /// values @p args.
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -1984,7 +1998,7 @@
     }
 
     /// @param source the array source
-    /// @param args the arguments for the array initializer
+    /// @param args the arguments for the array constructor
     /// @return an `ast::CallExpression` of an array with element type `T`, constructed with the
     /// values @p args.
     template <typename T, typename... ARGS>
@@ -1992,7 +2006,7 @@
         return Call(source, ty.array<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the array initializer
+    /// @param args the arguments for the array constructor
     /// @return an `ast::CallExpression` of an array with element type `T` and size `N`, constructed
     /// with the values @p args.
     template <typename T, int N, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -2001,7 +2015,7 @@
     }
 
     /// @param source the array source
-    /// @param args the arguments for the array initializer
+    /// @param args the arguments for the array constructor
     /// @return an `ast::CallExpression` of an array with element type `T` and size `N`, constructed
     /// with the values @p args.
     template <typename T, int N, typename... ARGS>
@@ -2011,7 +2025,7 @@
 
     /// @param subtype the array element type
     /// @param n the array size. nullptr represents a runtime-array.
-    /// @param args the arguments for the array initializer
+    /// @param args the arguments for the array constructor
     /// @return an `ast::CallExpression` of an array with element type
     /// `subtype`, constructed with the values @p args.
     template <typename EXPR, typename... ARGS>
@@ -2022,7 +2036,7 @@
     /// @param source the array source
     /// @param subtype the array element type
     /// @param n the array size. nullptr represents a runtime-array.
-    /// @param args the arguments for the array initializer
+    /// @param args the arguments for the array constructor
     /// @return an `ast::CallExpression` of an array with element type
     /// `subtype`, constructed with the values @p args.
     template <typename EXPR, typename... ARGS>
@@ -2055,11 +2069,11 @@
     /// @param name the variable name
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
-    ///   * ast::Type*          - specifies the variable type
-    ///   * type::AddressSpace   - specifies the variable address space
-    ///   * type::Access         - specifies the variable's access control
-    ///   * ast::Expression*    - specifies the variable's initializer expression
-    ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
+    ///   * ast::Type              - specifies the variable's type
+    ///   * builtin::AddressSpace  - specifies the variable's address space
+    ///   * builtin::Access        - specifies the variable's access control
+    ///   * ast::Expression*       - specifies the variable's initializer expression
+    ///   * ast::Attribute*        - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns a `ast::Var` with the given name, type and additional
     /// options
@@ -2072,16 +2086,16 @@
     /// @param name the variable name
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
-    ///   * ast::Type*          - specifies the variable type
-    ///   * type::AddressSpace   - specifies the variable address space
-    ///   * type::Access         - specifies the variable's access control
-    ///   * ast::Expression*    - specifies the variable's initializer expression
-    ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
+    ///   * ast::Type              - specifies the variable's type
+    ///   * builtin::AddressSpace  - specifies the variable's address space
+    ///   * builtin::Access        - specifies the variable's access control
+    ///   * ast::Expression*       - specifies the variable's initializer expression
+    ///   * ast::Attribute*        - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns a `ast::Var` with the given name, address_space and type
     template <typename NAME, typename... OPTIONS>
     const ast::Var* Var(const Source& source, NAME&& name, OPTIONS&&... options) {
-        VarOptions opts(std::forward<OPTIONS>(options)...);
+        VarOptions opts(*this, std::forward<OPTIONS>(options)...);
         return create<ast::Var>(source, Ident(std::forward<NAME>(name)), opts.type,
                                 opts.address_space, opts.access, opts.initializer,
                                 std::move(opts.attributes));
@@ -2091,8 +2105,7 @@
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
     ///   * ast::Expression*    - specifies the variable's initializer expression (required)
-    ///   * ast::Identifier*    - specifies the variable type
-    ///   * ast::Type*          - specifies the variable type
+    ///   * ast::Type           - specifies the variable's type
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns an `ast::Const` with the given name, type and additional options
@@ -2106,8 +2119,8 @@
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
     ///   * ast::Expression*    - specifies the variable's initializer expression (required)
-    ///   * ast::Identifier*    - specifies the variable type
-    ///   * ast::Type*          - specifies the variable type
+    ///   * ast::Identifier*    - specifies the variable's type
+    ///   * ast::Type           - specifies the variable's type
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns an `ast::Const` with the given name, type and additional options
@@ -2122,7 +2135,7 @@
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
     ///   * ast::Expression*    - specifies the variable's initializer expression (required)
-    ///   * ast::Type*          - specifies the variable type
+    ///   * ast::Type           - specifies the variable's type
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns an `ast::Let` with the given name, type and additional options
@@ -2136,7 +2149,7 @@
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
     ///   * ast::Expression*    - specifies the variable's initializer expression (required)
-    ///   * ast::Type*          - specifies the variable type
+    ///   * ast::Type           - specifies the variable's type
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns an `ast::Let` with the given name, type and additional options
@@ -2175,9 +2188,9 @@
     /// @param name the variable name
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
-    ///   * ast::Type*          - specifies the variable type
-    ///   * type::AddressSpace   - specifies the variable address space
-    ///   * type::Access         - specifies the variable's access control
+    ///   * ast::Type           - specifies the variable's type
+    ///   * builtin::AddressSpace   - specifies the variable address space
+    ///   * builtin::Access         - specifies the variable's access control
     ///   * ast::Expression*    - specifies the variable's initializer expression
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
@@ -2192,9 +2205,9 @@
     /// @param name the variable name
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
-    ///   * ast::Type*          - specifies the variable type
-    ///   * type::AddressSpace   - specifies the variable address space
-    ///   * type::Access         - specifies the variable's access control
+    ///   * ast::Type           - specifies the variable's type
+    ///   * builtin::AddressSpace   - specifies the variable address space
+    ///   * builtin::Access         - specifies the variable's access control
     ///   * ast::Expression*    - specifies the variable's initializer expression
     ///   * ast::Attribute*    - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
@@ -2211,7 +2224,7 @@
     /// @param options the extra options passed to the ast::Const initializer
     /// Can be any of the following, in any order:
     ///   * ast::Expression*    - specifies the variable's initializer expression (required)
-    ///   * ast::Type*          - specifies the variable type
+    ///   * ast::Type           - specifies the variable's type
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns an `ast::Const` with the given name, type and additional options, which is
@@ -2226,7 +2239,7 @@
     /// @param options the extra options passed to the ast::Const initializer
     /// Can be any of the following, in any order:
     ///   * ast::Expression*    - specifies the variable's initializer expression (required)
-    ///   * ast::Type*          - specifies the variable type
+    ///   * ast::Type           - specifies the variable's type
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns an `ast::Const` with the given name, type and additional options, which is
@@ -2242,7 +2255,7 @@
     /// @param options the extra options passed to the ast::Override initializer
     /// Can be any of the following, in any order:
     ///   * ast::Expression*    - specifies the variable's initializer expression (required)
-    ///   * ast::Type*          - specifies the variable type
+    ///   * ast::Type           - specifies the variable's type
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns an `ast::Override` with the given name, type and additional options, which is
@@ -2257,7 +2270,7 @@
     /// @param options the extra options passed to the ast::Override initializer
     /// Can be any of the following, in any order:
     ///   * ast::Expression*    - specifies the variable's initializer expression (required)
-    ///   * ast::Type*          - specifies the variable type
+    ///   * ast::Type           - specifies the variable's type
     ///   * ast::Attribute*     - specifies the variable's attributes (repeatable, or vector)
     /// Note that non-repeatable arguments of the same type will use the last argument's value.
     /// @returns an `ast::Override` with the given name, type and additional options, which is
@@ -2377,7 +2390,7 @@
                                               Expr(std::forward<EXPR>(expr)));
     }
 
-    /// @param args the arguments for the type constructor
+    /// @param args the arguments for the constructor
     /// @returns an ast::CallExpression to the type `T`, with the arguments of @p args converted to
     /// `ast::Expression`s using Expr().
     template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
@@ -2386,7 +2399,7 @@
     }
 
     /// @param source the source of the call
-    /// @param args the arguments for the type constructor
+    /// @param args the arguments for the constructor
     /// @returns an ast::CallExpression to the type `T` with the arguments of @p args converted to
     /// `ast::Expression`s using Expr().
     template <typename T, typename... ARGS>
@@ -3436,15 +3449,43 @@
     /// @param source the source information
     /// @param builtin the builtin value
     /// @returns the builtin attribute pointer
-    const ast::BuiltinAttribute* Builtin(const Source& source, builtin::BuiltinValue builtin) {
-        return create<ast::BuiltinAttribute>(source, builtin);
+    template <typename BUILTIN>
+    const ast::BuiltinAttribute* Builtin(const Source& source, BUILTIN&& builtin) {
+        return create<ast::BuiltinAttribute>(source, Expr(std::forward<BUILTIN>(builtin)));
     }
 
     /// Creates an ast::BuiltinAttribute
     /// @param builtin the builtin value
     /// @returns the builtin attribute pointer
-    const ast::BuiltinAttribute* Builtin(builtin::BuiltinValue builtin) {
-        return create<ast::BuiltinAttribute>(source_, builtin);
+    template <typename BUILTIN>
+    const ast::BuiltinAttribute* Builtin(BUILTIN&& builtin) {
+        return create<ast::BuiltinAttribute>(source_, Expr(std::forward<BUILTIN>(builtin)));
+    }
+
+    /// Creates an ast::InterpolateAttribute
+    /// @param type the interpolation type
+    /// @returns the interpolate attribute pointer
+    template <typename TYPE, typename = DisableIfSource<TYPE>>
+    const ast::InterpolateAttribute* Interpolate(TYPE&& type) {
+        return Interpolate(source_, std::forward<TYPE>(type));
+    }
+
+    /// Creates an ast::InterpolateAttribute
+    /// @param source the source information
+    /// @param type the interpolation type
+    /// @returns the interpolate attribute pointer
+    template <typename TYPE>
+    const ast::InterpolateAttribute* Interpolate(const Source& source, TYPE&& type) {
+        return create<ast::InterpolateAttribute>(source, Expr(std::forward<TYPE>(type)), nullptr);
+    }
+
+    /// Creates an ast::InterpolateAttribute
+    /// @param type the interpolation type
+    /// @param sampling the interpolation sampling
+    /// @returns the interpolate attribute pointer
+    template <typename TYPE, typename SAMPLING, typename = DisableIfSource<TYPE>>
+    const ast::InterpolateAttribute* Interpolate(TYPE&& type, SAMPLING&& sampling) {
+        return Interpolate(source_, std::forward<TYPE>(type), std::forward<SAMPLING>(sampling));
     }
 
     /// Creates an ast::InterpolateAttribute
@@ -3452,33 +3493,32 @@
     /// @param type the interpolation type
     /// @param sampling the interpolation sampling
     /// @returns the interpolate attribute pointer
-    const ast::InterpolateAttribute* Interpolate(
-        const Source& source,
-        ast::InterpolationType type,
-        ast::InterpolationSampling sampling = ast::InterpolationSampling::kUndefined) {
-        return create<ast::InterpolateAttribute>(source, type, sampling);
-    }
-
-    /// Creates an ast::InterpolateAttribute
-    /// @param type the interpolation type
-    /// @param sampling the interpolation sampling
-    /// @returns the interpolate attribute pointer
-    const ast::InterpolateAttribute* Interpolate(
-        ast::InterpolationType type,
-        ast::InterpolationSampling sampling = ast::InterpolationSampling::kUndefined) {
-        return create<ast::InterpolateAttribute>(source_, type, sampling);
+    template <typename TYPE, typename SAMPLING>
+    const ast::InterpolateAttribute* Interpolate(const Source& source,
+                                                 TYPE&& type,
+                                                 SAMPLING&& sampling) {
+        if constexpr (std::is_same_v<std::decay_t<SAMPLING>, builtin::InterpolationSampling>) {
+            if (sampling == builtin::InterpolationSampling::kUndefined) {
+                return create<ast::InterpolateAttribute>(source, Expr(std::forward<TYPE>(type)),
+                                                         nullptr);
+            }
+        }
+        return create<ast::InterpolateAttribute>(source, Expr(std::forward<TYPE>(type)),
+                                                 Expr(std::forward<SAMPLING>(sampling)));
     }
 
     /// Creates an ast::InterpolateAttribute using flat interpolation
     /// @param source the source information
     /// @returns the interpolate attribute pointer
     const ast::InterpolateAttribute* Flat(const Source& source) {
-        return Interpolate(source, ast::InterpolationType::kFlat);
+        return Interpolate(source, builtin::InterpolationType::kFlat);
     }
 
     /// Creates an ast::InterpolateAttribute using flat interpolation
     /// @returns the interpolate attribute pointer
-    const ast::InterpolateAttribute* Flat() { return Interpolate(ast::InterpolationType::kFlat); }
+    const ast::InterpolateAttribute* Flat() {
+        return Interpolate(builtin::InterpolationType::kFlat);
+    }
 
     /// Creates an ast::InvariantAttribute
     /// @param source the source information
@@ -3491,6 +3531,17 @@
     /// @returns the invariant attribute pointer
     const ast::InvariantAttribute* Invariant() { return create<ast::InvariantAttribute>(source_); }
 
+    /// Creates an ast::MustUseAttribute
+    /// @param source the source information
+    /// @returns the invariant attribute pointer
+    const ast::MustUseAttribute* MustUse(const Source& source) {
+        return create<ast::MustUseAttribute>(source);
+    }
+
+    /// Creates an ast::MustUseAttribute
+    /// @returns the invariant attribute pointer
+    const ast::MustUseAttribute* MustUse() { return create<ast::MustUseAttribute>(source_); }
+
     /// Creates an ast::LocationAttribute
     /// @param source the source information
     /// @param location the location value expression
@@ -3634,7 +3685,7 @@
     /// @returns the diagnostic attribute pointer
     template <typename NAME>
     const ast::DiagnosticAttribute* DiagnosticAttribute(const Source& source,
-                                                        ast::DiagnosticSeverity severity,
+                                                        builtin::DiagnosticSeverity severity,
                                                         NAME&& rule_name) {
         static_assert(!traits::IsType<traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
                       "it is invalid for a diagnostic rule name to be templated");
@@ -3647,7 +3698,7 @@
     /// @param rule_name the diagnostic rule name
     /// @returns the diagnostic attribute pointer
     template <typename NAME>
-    const ast::DiagnosticAttribute* DiagnosticAttribute(ast::DiagnosticSeverity severity,
+    const ast::DiagnosticAttribute* DiagnosticAttribute(builtin::DiagnosticSeverity severity,
                                                         NAME&& rule_name) {
         return create<ast::DiagnosticAttribute>(
             source_, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
@@ -3660,7 +3711,7 @@
     /// @returns the diagnostic directive pointer
     template <typename NAME>
     const ast::DiagnosticDirective* DiagnosticDirective(const Source& source,
-                                                        ast::DiagnosticSeverity severity,
+                                                        builtin::DiagnosticSeverity severity,
                                                         NAME&& rule_name) {
         auto* directive = create<ast::DiagnosticDirective>(
             source, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
@@ -3673,7 +3724,7 @@
     /// @param rule_name the diagnostic rule name
     /// @returns the diagnostic directive pointer
     template <typename NAME>
-    const ast::DiagnosticDirective* DiagnosticDirective(ast::DiagnosticSeverity severity,
+    const ast::DiagnosticDirective* DiagnosticDirective(builtin::DiagnosticSeverity severity,
                                                         NAME&& rule_name) {
         auto* directive = create<ast::DiagnosticDirective>(
             source_, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
diff --git a/src/tint/program_test.cc b/src/tint/program_test.cc
index f856504..0267bcc 100644
--- a/src/tint/program_test.cc
+++ b/src/tint/program_test.cc
@@ -46,7 +46,7 @@
 }
 
 TEST_F(ProgramTest, Assert_GlobalVariable) {
-    GlobalVar("var", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     Program program(std::move(*this));
     EXPECT_TRUE(program.IsValid());
diff --git a/src/tint/reader/spirv/attributes.h b/src/tint/reader/spirv/attributes.h
new file mode 100644
index 0000000..9014332
--- /dev/null
+++ b/src/tint/reader/spirv/attributes.h
@@ -0,0 +1,81 @@
+// Copyright 2023 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_TINT_READER_SPIRV_ATTRIBUTES_H_
+#define SRC_TINT_READER_SPIRV_ATTRIBUTES_H_
+
+#include "src/tint/ast/attribute.h"
+#include "src/tint/builtin/builtin_value.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/utils/enum_set.h"
+#include "src/tint/utils/vector.h"
+
+namespace tint::reader::spirv {
+
+/// Attributes holds a vector of ast::Attribute pointers, and a enum-set of flags used to hold
+/// additional metadata.
+struct Attributes {
+    /// Flags used by #flags.
+    enum class Flags {
+        kHasBuiltinSampleMask,
+    };
+
+    /// Adds the attributes and flags of @p other to this.
+    /// @param other the other Attributes to combine into this
+    void Add(const Attributes& other) {
+        for (auto* attr : other.list) {
+            list.Push(attr);
+        }
+        for (auto flag : other.flags) {
+            flags.Add(flag);
+        }
+    }
+
+    /// Adds the attribute @p attr to the list of attributes
+    /// @param attr the attribute to add to this
+    void Add(const ast::Attribute* attr) { list.Push(attr); }
+
+    /// Adds the builtin to the attribute list, also marking any necessary flags
+    /// @param builder the program builder
+    /// @param source the source of the builtin attribute
+    /// @param builtin the builtin attribute to add
+    void Add(ProgramBuilder& builder, const Source& source, builtin::BuiltinValue builtin) {
+        Add(builder.Builtin(source, builtin));
+        if (builtin == builtin::BuiltinValue::kSampleMask) {
+            flags.Add(Flags::kHasBuiltinSampleMask);
+        }
+    }
+
+    /// @returns true if the attribute list contains an attribute with the type `T`.
+    template <typename T>
+    bool Has() const {
+        return ast::HasAttribute<T>(list);
+    }
+
+    /// @returns the attribute with type `T` in the list, or nullptr if no attribute of the given
+    /// type exists in list.
+    template <typename T>
+    const T* Get() const {
+        return ast::GetAttribute<T>(list);
+    }
+
+    /// The attributes
+    utils::Vector<const ast::Attribute*, 8> list;
+    /// The additional metadata flags
+    utils::EnumSet<Flags> flags;
+};
+
+}  // namespace tint::reader::spirv
+
+#endif  // SRC_TINT_READER_SPIRV_ATTRIBUTES_H_
diff --git a/src/tint/reader/spirv/enum_converter.cc b/src/tint/reader/spirv/enum_converter.cc
index 41792ce..b4bca3b 100644
--- a/src/tint/reader/spirv/enum_converter.cc
+++ b/src/tint/reader/spirv/enum_converter.cc
@@ -38,30 +38,30 @@
     return ast::PipelineStage::kNone;
 }
 
-type::AddressSpace EnumConverter::ToAddressSpace(const spv::StorageClass sc) {
+builtin::AddressSpace EnumConverter::ToAddressSpace(const spv::StorageClass sc) {
     switch (sc) {
         case spv::StorageClass::Input:
-            return type::AddressSpace::kIn;
+            return builtin::AddressSpace::kIn;
         case spv::StorageClass::Output:
-            return type::AddressSpace::kOut;
+            return builtin::AddressSpace::kOut;
         case spv::StorageClass::Uniform:
-            return type::AddressSpace::kUniform;
+            return builtin::AddressSpace::kUniform;
         case spv::StorageClass::Workgroup:
-            return type::AddressSpace::kWorkgroup;
+            return builtin::AddressSpace::kWorkgroup;
         case spv::StorageClass::UniformConstant:
-            return type::AddressSpace::kNone;
+            return builtin::AddressSpace::kUndefined;
         case spv::StorageClass::StorageBuffer:
-            return type::AddressSpace::kStorage;
+            return builtin::AddressSpace::kStorage;
         case spv::StorageClass::Private:
-            return type::AddressSpace::kPrivate;
+            return builtin::AddressSpace::kPrivate;
         case spv::StorageClass::Function:
-            return type::AddressSpace::kFunction;
+            return builtin::AddressSpace::kFunction;
         default:
             break;
     }
 
     Fail() << "unknown SPIR-V storage class: " << uint32_t(sc);
-    return type::AddressSpace::kUndefined;
+    return builtin::AddressSpace::kUndefined;
 }
 
 builtin::BuiltinValue EnumConverter::ToBuiltin(spv::BuiltIn b) {
@@ -130,53 +130,53 @@
     return type::TextureDimension::kNone;
 }
 
-type::TexelFormat EnumConverter::ToTexelFormat(spv::ImageFormat fmt) {
+builtin::TexelFormat EnumConverter::ToTexelFormat(spv::ImageFormat fmt) {
     switch (fmt) {
         case spv::ImageFormat::Unknown:
-            return type::TexelFormat::kUndefined;
+            return builtin::TexelFormat::kUndefined;
 
         // 8 bit channels
         case spv::ImageFormat::Rgba8:
-            return type::TexelFormat::kRgba8Unorm;
+            return builtin::TexelFormat::kRgba8Unorm;
         case spv::ImageFormat::Rgba8Snorm:
-            return type::TexelFormat::kRgba8Snorm;
+            return builtin::TexelFormat::kRgba8Snorm;
         case spv::ImageFormat::Rgba8ui:
-            return type::TexelFormat::kRgba8Uint;
+            return builtin::TexelFormat::kRgba8Uint;
         case spv::ImageFormat::Rgba8i:
-            return type::TexelFormat::kRgba8Sint;
+            return builtin::TexelFormat::kRgba8Sint;
 
         // 16 bit channels
         case spv::ImageFormat::Rgba16ui:
-            return type::TexelFormat::kRgba16Uint;
+            return builtin::TexelFormat::kRgba16Uint;
         case spv::ImageFormat::Rgba16i:
-            return type::TexelFormat::kRgba16Sint;
+            return builtin::TexelFormat::kRgba16Sint;
         case spv::ImageFormat::Rgba16f:
-            return type::TexelFormat::kRgba16Float;
+            return builtin::TexelFormat::kRgba16Float;
 
         // 32 bit channels
         case spv::ImageFormat::R32ui:
-            return type::TexelFormat::kR32Uint;
+            return builtin::TexelFormat::kR32Uint;
         case spv::ImageFormat::R32i:
-            return type::TexelFormat::kR32Sint;
+            return builtin::TexelFormat::kR32Sint;
         case spv::ImageFormat::R32f:
-            return type::TexelFormat::kR32Float;
+            return builtin::TexelFormat::kR32Float;
         case spv::ImageFormat::Rg32ui:
-            return type::TexelFormat::kRg32Uint;
+            return builtin::TexelFormat::kRg32Uint;
         case spv::ImageFormat::Rg32i:
-            return type::TexelFormat::kRg32Sint;
+            return builtin::TexelFormat::kRg32Sint;
         case spv::ImageFormat::Rg32f:
-            return type::TexelFormat::kRg32Float;
+            return builtin::TexelFormat::kRg32Float;
         case spv::ImageFormat::Rgba32ui:
-            return type::TexelFormat::kRgba32Uint;
+            return builtin::TexelFormat::kRgba32Uint;
         case spv::ImageFormat::Rgba32i:
-            return type::TexelFormat::kRgba32Sint;
+            return builtin::TexelFormat::kRgba32Sint;
         case spv::ImageFormat::Rgba32f:
-            return type::TexelFormat::kRgba32Float;
+            return builtin::TexelFormat::kRgba32Float;
         default:
             break;
     }
     Fail() << "invalid image format: " << int(fmt);
-    return type::TexelFormat::kUndefined;
+    return builtin::TexelFormat::kUndefined;
 }
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/enum_converter.h b/src/tint/reader/spirv/enum_converter.h
index 7cdbfac..9a2a7b4 100644
--- a/src/tint/reader/spirv/enum_converter.h
+++ b/src/tint/reader/spirv/enum_converter.h
@@ -18,9 +18,9 @@
 #include "spirv/unified1/spirv.h"
 #include "spirv/unified1/spirv.hpp11"
 #include "src/tint/ast/pipeline_stage.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/builtin/builtin_value.h"
 #include "src/tint/reader/spirv/fail_stream.h"
-#include "src/tint/type/address_space.h"
 #include "src/tint/type/storage_texture.h"
 #include "src/tint/type/texture_dimension.h"
 
@@ -45,7 +45,7 @@
     /// On failure, logs an error and returns kNone
     /// @param sc the SPIR-V storage class
     /// @returns a Tint AST address space
-    type::AddressSpace ToAddressSpace(const spv::StorageClass sc);
+    builtin::AddressSpace ToAddressSpace(const spv::StorageClass sc);
 
     /// Converts a SPIR-V Builtin value a Tint Builtin.
     /// On failure, logs an error and returns kNone
@@ -73,13 +73,13 @@
     /// On failure, logs an error and returns kNone
     /// @param fmt the SPIR-V format
     /// @returns a Tint AST format
-    type::TexelFormat ToTexelFormat(spv::ImageFormat fmt);
+    builtin::TexelFormat ToTexelFormat(spv::ImageFormat fmt);
 
     /// Converts a SPIR-V Image Format to a TexelFormat
     /// On failure, logs an error and returns kNone
     /// @param fmt the SPIR-V format
     /// @returns a Tint AST format
-    type::TexelFormat ToTexelFormat(SpvImageFormat fmt) {
+    builtin::TexelFormat ToTexelFormat(SpvImageFormat fmt) {
         return ToTexelFormat(static_cast<spv::ImageFormat>(fmt));
     }
 
diff --git a/src/tint/reader/spirv/enum_converter_test.cc b/src/tint/reader/spirv/enum_converter_test.cc
index 4d1a8fd..407b121 100644
--- a/src/tint/reader/spirv/enum_converter_test.cc
+++ b/src/tint/reader/spirv/enum_converter_test.cc
@@ -85,7 +85,7 @@
 struct StorageClassCase {
     spv::StorageClass sc;
     bool expect_success;
-    type::AddressSpace expected;
+    builtin::AddressSpace expected;
 };
 inline std::ostream& operator<<(std::ostream& out, StorageClassCase scc) {
     out << "StorageClassCase{ spv::StorageClass:::" << int(scc.sc)
@@ -126,19 +126,21 @@
     EnumConverterGood,
     SpvStorageClassTest,
     testing::Values(
-        StorageClassCase{spv::StorageClass::Input, true, type::AddressSpace::kIn},
-        StorageClassCase{spv::StorageClass::Output, true, type::AddressSpace::kOut},
-        StorageClassCase{spv::StorageClass::Uniform, true, type::AddressSpace::kUniform},
-        StorageClassCase{spv::StorageClass::Workgroup, true, type::AddressSpace::kWorkgroup},
-        StorageClassCase{spv::StorageClass::UniformConstant, true, type::AddressSpace::kNone},
-        StorageClassCase{spv::StorageClass::StorageBuffer, true, type::AddressSpace::kStorage},
-        StorageClassCase{spv::StorageClass::Private, true, type::AddressSpace::kPrivate},
-        StorageClassCase{spv::StorageClass::Function, true, type::AddressSpace::kFunction}));
+        StorageClassCase{spv::StorageClass::Input, true, builtin::AddressSpace::kIn},
+        StorageClassCase{spv::StorageClass::Output, true, builtin::AddressSpace::kOut},
+        StorageClassCase{spv::StorageClass::Uniform, true, builtin::AddressSpace::kUniform},
+        StorageClassCase{spv::StorageClass::Workgroup, true, builtin::AddressSpace::kWorkgroup},
+        StorageClassCase{spv::StorageClass::UniformConstant, true,
+                         builtin::AddressSpace::kUndefined},
+        StorageClassCase{spv::StorageClass::StorageBuffer, true, builtin::AddressSpace::kStorage},
+        StorageClassCase{spv::StorageClass::Private, true, builtin::AddressSpace::kPrivate},
+        StorageClassCase{spv::StorageClass::Function, true, builtin::AddressSpace::kFunction}));
 
 INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
                          SpvStorageClassTest,
                          testing::Values(StorageClassCase{static_cast<spv::StorageClass>(9999),
-                                                          false, type::AddressSpace::kUndefined}));
+                                                          false,
+                                                          builtin::AddressSpace::kUndefined}));
 
 // Builtin
 
@@ -291,7 +293,7 @@
 struct TexelFormatCase {
     spv::ImageFormat format;
     bool expect_success;
-    type::TexelFormat expected;
+    builtin::TexelFormat expected;
 };
 inline std::ostream& operator<<(std::ostream& out, TexelFormatCase ifc) {
     out << "TexelFormatCase{ spv::ImageFormat:::" << int(ifc.format)
@@ -333,52 +335,52 @@
     SpvImageFormatTest,
     testing::Values(
         // Unknown.  This is used for sampled images.
-        TexelFormatCase{spv::ImageFormat::Unknown, true, type::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Unknown, true, builtin::TexelFormat::kUndefined},
         // 8 bit channels
-        TexelFormatCase{spv::ImageFormat::Rgba8, true, type::TexelFormat::kRgba8Unorm},
-        TexelFormatCase{spv::ImageFormat::Rgba8Snorm, true, type::TexelFormat::kRgba8Snorm},
-        TexelFormatCase{spv::ImageFormat::Rgba8ui, true, type::TexelFormat::kRgba8Uint},
-        TexelFormatCase{spv::ImageFormat::Rgba8i, true, type::TexelFormat::kRgba8Sint},
+        TexelFormatCase{spv::ImageFormat::Rgba8, true, builtin::TexelFormat::kRgba8Unorm},
+        TexelFormatCase{spv::ImageFormat::Rgba8Snorm, true, builtin::TexelFormat::kRgba8Snorm},
+        TexelFormatCase{spv::ImageFormat::Rgba8ui, true, builtin::TexelFormat::kRgba8Uint},
+        TexelFormatCase{spv::ImageFormat::Rgba8i, true, builtin::TexelFormat::kRgba8Sint},
         // 16 bit channels
-        TexelFormatCase{spv::ImageFormat::Rgba16ui, true, type::TexelFormat::kRgba16Uint},
-        TexelFormatCase{spv::ImageFormat::Rgba16i, true, type::TexelFormat::kRgba16Sint},
-        TexelFormatCase{spv::ImageFormat::Rgba16f, true, type::TexelFormat::kRgba16Float},
+        TexelFormatCase{spv::ImageFormat::Rgba16ui, true, builtin::TexelFormat::kRgba16Uint},
+        TexelFormatCase{spv::ImageFormat::Rgba16i, true, builtin::TexelFormat::kRgba16Sint},
+        TexelFormatCase{spv::ImageFormat::Rgba16f, true, builtin::TexelFormat::kRgba16Float},
         // 32 bit channels
         // ... 1 channel
-        TexelFormatCase{spv::ImageFormat::R32ui, true, type::TexelFormat::kR32Uint},
-        TexelFormatCase{spv::ImageFormat::R32i, true, type::TexelFormat::kR32Sint},
-        TexelFormatCase{spv::ImageFormat::R32f, true, type::TexelFormat::kR32Float},
+        TexelFormatCase{spv::ImageFormat::R32ui, true, builtin::TexelFormat::kR32Uint},
+        TexelFormatCase{spv::ImageFormat::R32i, true, builtin::TexelFormat::kR32Sint},
+        TexelFormatCase{spv::ImageFormat::R32f, true, builtin::TexelFormat::kR32Float},
         // ... 2 channels
-        TexelFormatCase{spv::ImageFormat::Rg32ui, true, type::TexelFormat::kRg32Uint},
-        TexelFormatCase{spv::ImageFormat::Rg32i, true, type::TexelFormat::kRg32Sint},
-        TexelFormatCase{spv::ImageFormat::Rg32f, true, type::TexelFormat::kRg32Float},
+        TexelFormatCase{spv::ImageFormat::Rg32ui, true, builtin::TexelFormat::kRg32Uint},
+        TexelFormatCase{spv::ImageFormat::Rg32i, true, builtin::TexelFormat::kRg32Sint},
+        TexelFormatCase{spv::ImageFormat::Rg32f, true, builtin::TexelFormat::kRg32Float},
         // ... 4 channels
-        TexelFormatCase{spv::ImageFormat::Rgba32ui, true, type::TexelFormat::kRgba32Uint},
-        TexelFormatCase{spv::ImageFormat::Rgba32i, true, type::TexelFormat::kRgba32Sint},
-        TexelFormatCase{spv::ImageFormat::Rgba32f, true, type::TexelFormat::kRgba32Float}));
+        TexelFormatCase{spv::ImageFormat::Rgba32ui, true, builtin::TexelFormat::kRgba32Uint},
+        TexelFormatCase{spv::ImageFormat::Rgba32i, true, builtin::TexelFormat::kRgba32Sint},
+        TexelFormatCase{spv::ImageFormat::Rgba32f, true, builtin::TexelFormat::kRgba32Float}));
 
 INSTANTIATE_TEST_SUITE_P(
     EnumConverterBad,
     SpvImageFormatTest,
     testing::Values(
         // Scanning in order from the SPIR-V spec.
-        TexelFormatCase{spv::ImageFormat::Rg16f, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::R11fG11fB10f, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::R16f, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rgb10A2, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rg16, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rg8, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::R16, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::R8, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rgba16Snorm, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rg16Snorm, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rg8Snorm, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rg16i, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rg8i, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::R8i, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rgb10a2ui, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rg16ui, false, type::TexelFormat::kUndefined},
-        TexelFormatCase{spv::ImageFormat::Rg8ui, false, type::TexelFormat::kUndefined}));
+        TexelFormatCase{spv::ImageFormat::Rg16f, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::R11fG11fB10f, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::R16f, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rgb10A2, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rg16, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rg8, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::R16, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::R8, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rgba16Snorm, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rg16Snorm, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rg8Snorm, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rg16i, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rg8i, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::R8i, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rgb10a2ui, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rg16ui, false, builtin::TexelFormat::kUndefined},
+        TexelFormatCase{spv::ImageFormat::Rg8ui, false, builtin::TexelFormat::kUndefined}));
 
 }  // namespace
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index d63a8f1..49d4e83 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -756,15 +756,6 @@
     mutable const ast::BlockStatement* continuing = nullptr;
 };
 
-/// @param decos a list of parsed decorations
-/// @returns true if the decorations include a SampleMask builtin
-bool HasBuiltinSampleMask(utils::VectorRef<const ast::Attribute*> decos) {
-    if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(decos)) {
-        return builtin->builtin == builtin::BuiltinValue::kSampleMask;
-    }
-    return false;
-}
-
 }  // namespace
 
 BlockInfo::BlockInfo(const spvtools::opt::BasicBlock& bb) : basic_block(&bb), id(bb.id()) {}
@@ -956,7 +947,7 @@
         }
 
         builder_.Func(decl.source, decl.name, std::move(decl.params),
-                      decl.return_type->Build(builder_), body, std::move(decl.attributes));
+                      decl.return_type->Build(builder_), body, std::move(decl.attributes.list));
     }
 
     if (ep_info_ && !ep_info_->inner_name.empty()) {
@@ -994,12 +985,12 @@
 
 bool FunctionEmitter::EmitPipelineInput(std::string var_name,
                                         const Type* var_type,
-                                        AttributeList* attrs,
                                         utils::Vector<int, 8> index_prefix,
                                         const Type* tip_type,
                                         const Type* forced_param_type,
-                                        ParameterList* params,
-                                        StatementList* statements) {
+                                        Attributes& attrs,
+                                        ParameterList& params,
+                                        StatementList& statements) {
     // TODO(dneto): Handle structs where the locations are annotated on members.
     tip_type = tip_type->UnwrapAlias();
     if (auto* ref_type = tip_type->As<Reference>()) {
@@ -1015,8 +1006,8 @@
             const Type* vec_ty = ty_.Vector(matrix_type->type, matrix_type->rows);
             for (int col = 0; col < num_columns; col++) {
                 index_prefix.Back() = col;
-                if (!EmitPipelineInput(var_name, var_type, attrs, index_prefix, vec_ty,
-                                       forced_param_type, params, statements)) {
+                if (!EmitPipelineInput(var_name, var_type, index_prefix, vec_ty, forced_param_type,
+                                       attrs, params, statements)) {
                     return false;
                 }
             }
@@ -1030,8 +1021,8 @@
             const Type* elem_ty = array_type->type;
             for (int i = 0; i < static_cast<int>(array_type->size); i++) {
                 index_prefix.Back() = i;
-                if (!EmitPipelineInput(var_name, var_type, attrs, index_prefix, elem_ty,
-                                       forced_param_type, params, statements)) {
+                if (!EmitPipelineInput(var_name, var_type, index_prefix, elem_ty, forced_param_type,
+                                       attrs, params, statements)) {
                     return false;
                 }
             }
@@ -1042,38 +1033,36 @@
             index_prefix.Push(0);
             for (size_t i = 0; i < members.size(); ++i) {
                 index_prefix.Back() = static_cast<int>(i);
-                AttributeList member_attrs(*attrs);
+                Attributes member_attrs(attrs);
                 if (!parser_impl_.ConvertPipelineDecorations(
                         struct_type,
                         parser_impl_.GetMemberPipelineDecorations(*struct_type,
                                                                   static_cast<int>(i)),
-                        &member_attrs)) {
+                        member_attrs)) {
                     return false;
                 }
-                if (!EmitPipelineInput(var_name, var_type, &member_attrs, index_prefix, members[i],
-                                       forced_param_type, params, statements)) {
+                if (!EmitPipelineInput(var_name, var_type, index_prefix, members[i],
+                                       forced_param_type, member_attrs, params, statements)) {
                     return false;
                 }
                 // Copy the location as updated by nested expansion of the member.
-                parser_impl_.SetLocation(attrs,
-                                         ast::GetAttribute<ast::LocationAttribute>(member_attrs));
+                parser_impl_.SetLocation(attrs, member_attrs.Get<ast::LocationAttribute>());
             }
             return success();
         },
         [&](Default) {
-            const bool is_builtin = ast::HasAttribute<ast::BuiltinAttribute>(*attrs);
+            const bool is_builtin = attrs.Has<ast::BuiltinAttribute>();
 
             const Type* param_type = is_builtin ? forced_param_type : tip_type;
 
             const auto param_name = namer_.MakeDerivedName(var_name + "_param");
             // Create the parameter.
-            // TODO(dneto): Note: If the parameter has non-location decorations,
-            // then those decoration AST nodes will be reused between multiple
-            // elements of a matrix, array, or structure.  Normally that's
-            // disallowed but currently the SPIR-V reader will make duplicates when
-            // the entire AST is cloned at the top level of the SPIR-V reader flow.
+            // TODO(dneto): Note: If the parameter has non-location decorations, then those
+            // decoration AST nodes will be reused between multiple elements of a matrix, array, or
+            // structure.  Normally that's disallowed but currently the SPIR-V reader will make
+            // duplicates when the entire AST is cloned at the top level of the SPIR-V reader flow.
             // Consider rewriting this to avoid this node-sharing.
-            params->Push(builder_.Param(param_name, param_type->Build(builder_), *attrs));
+            params.Push(builder_.Param(param_name, param_type->Build(builder_), attrs.list));
 
             // Add a body statement to copy the parameter to the corresponding
             // private variable.
@@ -1101,27 +1090,25 @@
             }
 
             if (is_builtin && (tip_type != forced_param_type)) {
-                // The parameter will have the WGSL type, but we need bitcast to
-                // the variable store type.
+                // The parameter will have the WGSL type, but we need bitcast to the variable store
+                // type.
                 param_value = builder_.Bitcast(tip_type->Build(builder_), param_value);
             }
 
-            statements->Push(builder_.Assign(store_dest, param_value));
+            statements.Push(builder_.Assign(store_dest, param_value));
 
-            // Increment the location attribute, in case more parameters will
-            // follow.
+            // Increment the location attribute, in case more parameters will follow.
             IncrementLocation(attrs);
 
             return success();
         });
 }
 
-void FunctionEmitter::IncrementLocation(AttributeList* attributes) {
-    for (auto*& attr : *attributes) {
+void FunctionEmitter::IncrementLocation(Attributes& attributes) {
+    for (auto*& attr : attributes.list) {
         if (auto* loc_attr = attr->As<ast::LocationAttribute>()) {
             // Replace this location attribute with a new one with one higher index.
-            // The old one doesn't leak because it's kept in the builder's AST node
-            // list.
+            // The old one doesn't leak because it's kept in the builder's AST node list.
             attr = builder_.Location(
                 loc_attr->source, AInt(loc_attr->expr->As<ast::IntLiteralExpression>()->value + 1));
         }
@@ -1130,12 +1117,12 @@
 
 bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
                                          const Type* var_type,
-                                         AttributeList* decos,
                                          utils::Vector<int, 8> index_prefix,
                                          const Type* tip_type,
                                          const Type* forced_member_type,
-                                         StructMemberList* return_members,
-                                         ExpressionList* return_exprs) {
+                                         Attributes& attrs,
+                                         StructMemberList& return_members,
+                                         ExpressionList& return_exprs) {
     tip_type = tip_type->UnwrapAlias();
     if (auto* ref_type = tip_type->As<Reference>()) {
         tip_type = ref_type->type;
@@ -1150,8 +1137,8 @@
             const Type* vec_ty = ty_.Vector(matrix_type->type, matrix_type->rows);
             for (int col = 0; col < num_columns; col++) {
                 index_prefix.Back() = col;
-                if (!EmitPipelineOutput(var_name, var_type, std::move(decos), index_prefix, vec_ty,
-                                        forced_member_type, return_members, return_exprs)) {
+                if (!EmitPipelineOutput(var_name, var_type, index_prefix, vec_ty,
+                                        forced_member_type, attrs, return_members, return_exprs)) {
                     return false;
                 }
             }
@@ -1165,8 +1152,8 @@
             const Type* elem_ty = array_type->type;
             for (int i = 0; i < static_cast<int>(array_type->size); i++) {
                 index_prefix.Back() = i;
-                if (!EmitPipelineOutput(var_name, var_type, std::move(decos), index_prefix, elem_ty,
-                                        forced_member_type, return_members, return_exprs)) {
+                if (!EmitPipelineOutput(var_name, var_type, index_prefix, elem_ty,
+                                        forced_member_type, attrs, return_members, return_exprs)) {
                     return false;
                 }
             }
@@ -1177,39 +1164,37 @@
             index_prefix.Push(0);
             for (int i = 0; i < static_cast<int>(members.size()); ++i) {
                 index_prefix.Back() = i;
-                AttributeList member_attrs(*decos);
+                Attributes member_attrs(attrs);
                 if (!parser_impl_.ConvertPipelineDecorations(
                         struct_type, parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
-                        &member_attrs)) {
+                        member_attrs)) {
                     return false;
                 }
-                if (!EmitPipelineOutput(var_name, var_type, &member_attrs, index_prefix,
+                if (!EmitPipelineOutput(var_name, var_type, index_prefix,
                                         members[static_cast<size_t>(i)], forced_member_type,
-                                        return_members, return_exprs)) {
+                                        member_attrs, return_members, return_exprs)) {
                     return false;
                 }
                 // Copy the location as updated by nested expansion of the member.
-                parser_impl_.SetLocation(decos,
-                                         ast::GetAttribute<ast::LocationAttribute>(member_attrs));
+                parser_impl_.SetLocation(attrs, member_attrs.Get<ast::LocationAttribute>());
             }
             return success();
         },
         [&](Default) {
-            const bool is_builtin = ast::HasAttribute<ast::BuiltinAttribute>(*decos);
+            const bool is_builtin = attrs.Has<ast::BuiltinAttribute>();
 
             const Type* member_type = is_builtin ? forced_member_type : tip_type;
             // Derive the member name directly from the variable name.  They can't
             // collide.
             const auto member_name = namer_.MakeDerivedName(var_name);
             // Create the member.
-            // TODO(dneto): Note: If the parameter has non-location decorations,
-            // then those decoration AST nodes  will be reused between multiple
-            // elements of a matrix, array, or structure.  Normally that's
-            // disallowed but currently the SPIR-V reader will make duplicates when
-            // the entire AST is cloned at the top level of the SPIR-V reader flow.
+            // TODO(dneto): Note: If the parameter has non-location decorations, then those
+            // decoration AST nodes  will be reused between multiple elements of a matrix, array, or
+            // structure.  Normally that's disallowed but currently the SPIR-V reader will make
+            // duplicates when the entire AST is cloned at the top level of the SPIR-V reader flow.
             // Consider rewriting this to avoid this node-sharing.
-            return_members->Push(
-                builder_.Member(member_name, member_type->Build(builder_), *decos));
+            return_members.Push(
+                builder_.Member(member_name, member_type->Build(builder_), attrs.list));
 
             // Create an expression to evaluate the part of the variable indexed by
             // the index_prefix.
@@ -1240,11 +1225,10 @@
                 // the variable store type.
                 load_source = builder_.Bitcast(forced_member_type->Build(builder_), load_source);
             }
-            return_exprs->Push(load_source);
+            return_exprs.Push(load_source);
 
-            // Increment the location attribute, in case more parameters will
-            // follow.
-            IncrementLocation(decos);
+            // Increment the location attribute, in case more parameters will follow.
+            IncrementLocation(attrs);
 
             return success();
         });
@@ -1270,8 +1254,8 @@
         TINT_ASSERT(Reader, opcode(var) == spv::Op::OpVariable);
         auto* store_type = GetVariableStoreType(*var);
         auto* forced_param_type = store_type;
-        AttributeList param_decos;
-        if (!parser_impl_.ConvertDecorationsForVariable(var_id, &forced_param_type, &param_decos,
+        Attributes param_attrs;
+        if (!parser_impl_.ConvertDecorationsForVariable(var_id, &forced_param_type, param_attrs,
                                                         true)) {
             // This occurs, and is not an error, for the PointSize builtin.
             if (!success()) {
@@ -1287,18 +1271,17 @@
         const auto var_name = namer_.GetName(var_id);
 
         bool ok = true;
-        if (HasBuiltinSampleMask(param_decos)) {
+        if (param_attrs.flags.Contains(Attributes::Flags::kHasBuiltinSampleMask)) {
             // In Vulkan SPIR-V, the sample mask is an array. In WGSL it's a scalar.
             // Use the first element only.
             auto* sample_mask_array_type = store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
             TINT_ASSERT(Reader, sample_mask_array_type);
-            ok = EmitPipelineInput(var_name, store_type, &param_decos, {0},
-                                   sample_mask_array_type->type, forced_param_type, &decl.params,
-                                   &stmts);
+            ok = EmitPipelineInput(var_name, store_type, {0}, sample_mask_array_type->type,
+                                   forced_param_type, param_attrs, decl.params, stmts);
         } else {
             // The normal path.
-            ok = EmitPipelineInput(var_name, store_type, &param_decos, {}, store_type,
-                                   forced_param_type, &decl.params, &stmts);
+            ok = EmitPipelineInput(var_name, store_type, {}, store_type, forced_param_type,
+                                   param_attrs, decl.params, stmts);
         }
         if (!ok) {
             return false;
@@ -1330,12 +1313,12 @@
                 // The SPIR-V gl_PerVertex variable has already been remapped to
                 // a gl_Position variable.  Substitute the type.
                 const Type* param_type = ty_.Vector(ty_.F32(), 4);
-                AttributeList out_decos{
-                    create<ast::BuiltinAttribute>(source, builtin::BuiltinValue::kPosition)};
-
                 const auto var_name = namer_.GetName(var_id);
                 return_members.Push(
-                    builder_.Member(var_name, param_type->Build(builder_), out_decos));
+                    builder_.Member(var_name, param_type->Build(builder_),
+                                    utils::Vector{
+                                        builder_.Builtin(source, builtin::BuiltinValue::kPosition),
+                                    }));
                 return_exprs.Push(builder_.Expr(var_name));
 
             } else {
@@ -1344,9 +1327,9 @@
                 TINT_ASSERT(Reader, opcode(var) == spv::Op::OpVariable);
                 const Type* store_type = GetVariableStoreType(*var);
                 const Type* forced_member_type = store_type;
-                AttributeList out_decos;
+                Attributes out_attrs;
                 if (!parser_impl_.ConvertDecorationsForVariable(var_id, &forced_member_type,
-                                                                &out_decos, true)) {
+                                                                out_attrs, true)) {
                     // This occurs, and is not an error, for the PointSize builtin.
                     if (!success()) {
                         // But exit early if an error was logged.
@@ -1357,19 +1340,20 @@
 
                 const auto var_name = namer_.GetName(var_id);
                 bool ok = true;
-                if (HasBuiltinSampleMask(out_decos)) {
+                if (out_attrs.flags.Contains(Attributes::Flags::kHasBuiltinSampleMask)) {
                     // In Vulkan SPIR-V, the sample mask is an array. In WGSL it's a
                     // scalar. Use the first element only.
                     auto* sample_mask_array_type =
                         store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
                     TINT_ASSERT(Reader, sample_mask_array_type);
-                    ok = EmitPipelineOutput(var_name, store_type, &out_decos, {0},
-                                            sample_mask_array_type->type, forced_member_type,
-                                            &return_members, &return_exprs);
+                    ok = EmitPipelineOutput(var_name, store_type, {0}, sample_mask_array_type->type,
+                                            forced_member_type, out_attrs, return_members,
+                                            return_exprs);
                 } else {
                     // The normal path.
-                    ok = EmitPipelineOutput(var_name, store_type, &out_decos, {}, store_type,
-                                            forced_member_type, &return_members, &return_exprs);
+                    ok =
+                        EmitPipelineOutput(var_name, store_type, {}, store_type, forced_member_type,
+                                           out_attrs, return_members, return_exprs);
                 }
                 if (!ok) {
                     return false;
@@ -1384,7 +1368,7 @@
         } else {
             // Create and register the result type.
             auto* str = create<ast::Struct>(Source{}, builder_.Ident(return_struct_sym),
-                                            return_members, AttributeList{});
+                                            return_members, utils::Empty);
             parser_impl_.AddTypeDecl(return_struct_sym, str);
             return_type = builder_.ty.Of(str);
 
@@ -1394,8 +1378,9 @@
         }
     }
 
-    AttributeList fn_attrs;
-    fn_attrs.Push(create<ast::StageAttribute>(source, ep_info_->stage));
+    utils::Vector<const ast::Attribute*, 2> fn_attrs{
+        create<ast::StageAttribute>(source, ep_info_->stage),
+    };
 
     if (ep_info_->stage == ast::PipelineStage::kCompute) {
         auto& size = ep_info_->workgroup_size;
@@ -1442,7 +1427,7 @@
                                      : parser_impl_.ConvertType(param->type_id());
 
         if (type != nullptr) {
-            auto* ast_param = parser_impl_.MakeParameter(param->result_id(), type, AttributeList{});
+            auto* ast_param = parser_impl_.MakeParameter(param->result_id(), type, Attributes{});
             // Parameters are treated as const declarations.
             ast_params.Push(ast_param);
             // The value is accessible by name.
@@ -1458,7 +1443,7 @@
     decl->name = name;
     decl->params = std::move(ast_params);
     decl->return_type = ret_ty;
-    decl->attributes.Clear();
+    decl->attributes = {};
 
     return success();
 }
@@ -2521,11 +2506,12 @@
                 return false;
             }
         }
-        auto* var = parser_impl_.MakeVar(inst.result_id(), type::AddressSpace::kNone,
-                                         var_store_type, initializer, AttributeList{});
+        auto* var = parser_impl_.MakeVar(inst.result_id(), builtin::AddressSpace::kUndefined,
+                                         builtin::Access::kUndefined, var_store_type, initializer,
+                                         Attributes{});
         auto* var_decl_stmt = create<ast::VariableDeclStatement>(Source{}, var);
         AddStatement(var_decl_stmt);
-        auto* var_type = ty_.Reference(var_store_type, type::AddressSpace::kNone);
+        auto* var_type = ty_.Reference(var_store_type, builtin::AddressSpace::kUndefined);
         identifier_types_.emplace(inst.result_id(), var_type);
     }
     return success();
@@ -3367,9 +3353,10 @@
         // no need to remap pointer properties.
         auto* store_type = parser_impl_.ConvertType(def_inst->type_id());
         AddStatement(create<ast::VariableDeclStatement>(
-            Source{}, parser_impl_.MakeVar(id, type::AddressSpace::kNone, store_type, nullptr,
-                                           AttributeList{})));
-        auto* type = ty_.Reference(store_type, type::AddressSpace::kNone);
+            Source{},
+            parser_impl_.MakeVar(id, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
+                                 store_type, nullptr, Attributes{})));
+        auto* type = ty_.Reference(store_type, builtin::AddressSpace::kUndefined);
         identifier_types_.emplace(id, type);
     }
 
@@ -3963,7 +3950,7 @@
 
     if (ext_opcode == GLSLstd450Ldexp) {
         // WGSL requires the second argument to be signed.
-        // Use a type initializer to convert it, which is the same as a bitcast.
+        // Use a value constructor to convert it, which is the same as a bitcast.
         // If the value would go from very large positive to negative, then the
         // original result would have been infinity.  And since WGSL
         // implementations may assume that infinities are not present, then we
@@ -4835,13 +4822,13 @@
         // either variables or function parameters.
         switch (opcode(inst)) {
             case spv::Op::OpVariable: {
-                if (const auto* module_var = parser_impl_.GetModuleVariable(id)) {
-                    return DefInfo::Pointer{module_var->declared_address_space,
-                                            module_var->declared_access};
+                if (auto v = parser_impl_.GetModuleVariable(id); v.var) {
+                    return DefInfo::Pointer{v.address_space, v.access};
                 }
                 // Local variables are always Function storage class, with default
                 // access mode.
-                return DefInfo::Pointer{type::AddressSpace::kFunction, type::Access::kUndefined};
+                return DefInfo::Pointer{builtin::AddressSpace::kFunction,
+                                        builtin::Access::kUndefined};
             }
             case spv::Op::OpFunctionParameter: {
                 const auto* type = As<Pointer>(parser_impl_.ConvertType(inst.type_id()));
@@ -4854,7 +4841,7 @@
                 // parameters.  In that case we need to do a global analysis to
                 // determine what the formal argument parameter type should be,
                 // whether it has read_only or read_write access mode.
-                return DefInfo::Pointer{type->address_space, type::Access::kUndefined};
+                return DefInfo::Pointer{type->address_space, builtin::Access::kUndefined};
             }
             default:
                 break;
@@ -5081,7 +5068,7 @@
             // Avoid moving combinatorial values across constructs.  This is a
             // simple heuristic to avoid changing the cost of an operation
             // by moving it into or out of a loop, for example.
-            if ((def_info->pointer.address_space == type::AddressSpace::kUndefined) &&
+            if ((def_info->pointer.address_space == builtin::AddressSpace::kUndefined) &&
                 local_def.used_in_another_construct) {
                 should_hoist_to_let = true;
             }
@@ -6190,8 +6177,8 @@
         // API in parser_impl_.
         var_name = namer_.MakeDerivedName(original_value_name);
 
-        auto* temp_var = builder_.Var(var_name, type->Build(builder_), type::AddressSpace::kNone,
-                                      src_vector.expr);
+        auto* temp_var = builder_.Var(var_name, type->Build(builder_),
+                                      builtin::AddressSpace::kUndefined, src_vector.expr);
 
         AddStatement(builder_.Decl({}, temp_var));
     }
@@ -6260,8 +6247,8 @@
         // It doesn't correspond to a SPIR-V ID, so we don't use the ordinary
         // API in parser_impl_.
         var_name = namer_.MakeDerivedName(original_value_name);
-        auto* temp_var = builder_.Var(var_name, type->Build(builder_), type::AddressSpace::kNone,
-                                      src_composite.expr);
+        auto* temp_var = builder_.Var(var_name, type->Build(builder_),
+                                      builtin::AddressSpace::kUndefined, src_composite.expr);
         AddStatement(builder_.Decl({}, temp_var));
     }
 
diff --git a/src/tint/reader/spirv/function.h b/src/tint/reader/spirv/function.h
index 5349537..a07309d 100644
--- a/src/tint/reader/spirv/function.h
+++ b/src/tint/reader/spirv/function.h
@@ -25,6 +25,7 @@
 #include <vector>
 
 #include "src/tint/program_builder.h"
+#include "src/tint/reader/spirv/attributes.h"
 #include "src/tint/reader/spirv/construct.h"
 #include "src/tint/reader/spirv/parser_impl.h"
 
@@ -331,10 +332,10 @@
         /// buffer expressed in the old style (with Uniform address space)
         /// that needs to be remapped to StorageBuffer address space.
         /// This is kInvalid for non-pointers.
-        type::AddressSpace address_space = type::AddressSpace::kUndefined;
+        builtin::AddressSpace address_space = builtin::AddressSpace::kUndefined;
 
         /// The declared access mode.
-        type::Access access = type::Access::kUndefined;
+        builtin::Access access = builtin::Access::kUndefined;
     };
 
     /// The expression to use when sinking pointers into their use.
@@ -368,7 +369,7 @@
     }
     o << " requires_named_let_def: " << (di.requires_named_let_def ? "true" : "false")
       << " requires_hoisted_var_def: " << (di.requires_hoisted_var_def ? "true" : "false");
-    if (di.pointer.address_space != type::AddressSpace::kNone) {
+    if (di.pointer.address_space != builtin::AddressSpace::kUndefined) {
         o << " sc:" << int(di.pointer.address_space);
     }
     switch (di.skip) {
@@ -420,7 +421,6 @@
 
 /// A FunctionEmitter emits a SPIR-V function onto a Tint AST module.
 class FunctionEmitter {
-    using AttributeList = utils::Vector<const ast::Attribute*, 8>;
     using StructMemberList = utils::Vector<const ast::StructMember*, 8>;
     using ExpressionList = utils::Vector<const ast::Expression*, 8>;
     using ParameterList = utils::Vector<const ast::Parameter*, 8>;
@@ -473,32 +473,31 @@
     /// @returns false if emission failed.
     bool EmitEntryPointAsWrapper();
 
-    /// Creates one or more entry point input parameters corresponding to a
-    /// part of an input variable.  The part of the input variable is specfied
-    /// by the `index_prefix`, which successively indexes into the variable.
-    /// Also generates the assignment statements that copy the input parameter
-    /// to the corresponding part of the variable.  Assumes the variable
-    /// has already been created in the Private address space.
+    /// Creates one or more entry point input parameters corresponding to a part of an input
+    /// variable.  The part of the input variable is specfied by the `index_prefix`, which
+    /// successively indexes into the variable. Also generates the assignment statements that copy
+    /// the input parameter to the corresponding part of the variable.  Assumes the variable has
+    /// already been created in the Private address space.
     /// @param var_name The name of the variable
     /// @param var_type The store type of the variable
-    /// @param decos The variable's decorations
-    /// @param index_prefix Indices stepping into the variable, indicating
-    /// what part of the variable to populate.
-    /// @param tip_type The type of the component inside variable, after indexing
-    /// with the indices in `index_prefix`.
-    /// @param forced_param_type The type forced by WGSL, if the variable is a
-    /// builtin, otherwise the same as var_type.
+    /// @param attributes The variable's attributes
+    /// @param index_prefix Indices stepping into the variable, indicating what part of the variable
+    /// to populate.
+    /// @param tip_type The type of the component inside variable, after indexing with the indices
+    /// in `index_prefix`.
+    /// @param forced_param_type The type forced by WGSL, if the variable is a builtin, otherwise
+    /// the same as var_type.
     /// @param params The parameter list where the new parameter is appended.
     /// @param statements The statement list where the assignment is appended.
     /// @returns false if emission failed
     bool EmitPipelineInput(std::string var_name,
                            const Type* var_type,
-                           AttributeList* decos,
                            utils::Vector<int, 8> index_prefix,
                            const Type* tip_type,
                            const Type* forced_param_type,
-                           ParameterList* params,
-                           StatementList* statements);
+                           Attributes& attributes,
+                           ParameterList& params,
+                           StatementList& statements);
 
     /// Creates one or more struct members from an output variable, and the
     /// expressions that compute the value they contribute to the entry point
@@ -507,31 +506,31 @@
     /// Assumes the variable has already been created in the Private address space
     /// @param var_name The name of the variable
     /// @param var_type The store type of the variable
-    /// @param decos The variable's decorations
     /// @param index_prefix Indices stepping into the variable, indicating what part of the variable
     /// to populate.
     /// @param tip_type The type of the component inside variable, after indexing with the indices
     /// in `index_prefix`.
     /// @param forced_member_type The type forced by WGSL, if the variable is a builtin, otherwise
     /// the same as var_type.
+    /// @param attributes The variable's attributes
     /// @param return_members The struct member list where the new member is added.
     /// @param return_exprs The expression list where the return expression is added.
     /// @returns false if emission failed
     bool EmitPipelineOutput(std::string var_name,
                             const Type* var_type,
-                            AttributeList* decos,
                             utils::Vector<int, 8> index_prefix,
                             const Type* tip_type,
                             const Type* forced_member_type,
-                            StructMemberList* return_members,
-                            ExpressionList* return_exprs);
+                            Attributes& attributes,
+                            StructMemberList& return_members,
+                            ExpressionList& return_exprs);
 
     /// Updates the attribute list, replacing an existing Location attribute
     /// with another having one higher location value. Does nothing if no
     /// location attribute exists.
     /// Assumes the list contains at most one Location attribute.
     /// @param attributes the attribute list to modify
-    void IncrementLocation(AttributeList* attributes);
+    void IncrementLocation(Attributes& attributes);
 
     /// Create an ast::BlockStatement representing the body of the function.
     /// This creates the statement stack, which is non-empty for the lifetime
@@ -976,7 +975,7 @@
         /// Function return type
         const Type* return_type;
         /// Function attributes
-        AttributeList attributes;
+        Attributes attributes;
     };
 
     /// Parse the function declaration, which comprises the name, parameters, and
diff --git a/src/tint/reader/spirv/namer.cc b/src/tint/reader/spirv/namer.cc
index 1233157..3e1f880 100644
--- a/src/tint/reader/spirv/namer.cc
+++ b/src/tint/reader/spirv/namer.cc
@@ -26,32 +26,146 @@
 
 const char* kWGSLReservedWords[] = {
     // Please keep this list sorted
-    "array",      "as",          "asm",
-    "bf16",       "binding",     "block",
-    "bool",       "break",       "builtin",
-    "case",       "cast",        "compute",
-    "const",      "continue",    "default",
-    "discard",    "do",          "else",
-    "elseif",     "entry_point", "enum",
-    "f16",        "f32",         "fallthrough",
-    "false",      "fn",          "for",
-    "fragment",   "i16",         "i32",
-    "i64",        "i8",          "if",
-    "image",      "import",      "in",
-    "let",        "location",    "loop",
-    "mat2x2",     "mat2x3",      "mat2x4",
-    "mat3x2",     "mat3x3",      "mat3x4",
-    "mat4x2",     "mat4x3",      "mat4x4",
-    "offset",     "out",         "override",
-    "premerge",   "private",     "ptr",
-    "regardless", "return",      "set",
-    "storage",    "struct",      "switch",
-    "true",       "type",        "typedef",
-    "u16",        "u32",         "u64",
-    "u8",         "uniform",     "uniform_constant",
-    "unless",     "using",       "var",
-    "vec2",       "vec3",        "vec4",
-    "vertex",     "void",        "while",
+    "array",
+    "as",
+    "asm",
+    "atomic",
+    "bf16",
+    "binding",
+    "block",
+    "bool",
+    "break",
+    "builtin",
+    "case",
+    "cast",
+    "compute",
+    "const",
+    "continue",
+    "default",
+    "discard",
+    "do",
+    "else",
+    "elseif",
+    "entry_point",
+    "enum",
+    "f16",
+    "f32",
+    "fallthrough",
+    "false",
+    "fn",
+    "for",
+    "frag_depth",
+    "fragment",
+    "front_facing",
+    "global_invocation_id",
+    "i16",
+    "i32",
+    "i64",
+    "i8",
+    "if",
+    "image",
+    "import",
+    "in",
+    "instance_index",
+    "let",
+    "local_invocation_id",
+    "local_invocation_index",
+    "location",
+    "loop",
+    "mat2x2",
+    "mat2x2f",
+    "mat2x2h",
+    "mat2x3",
+    "mat2x3f",
+    "mat2x3h",
+    "mat2x4",
+    "mat2x4f",
+    "mat2x4h",
+    "mat3x2",
+    "mat3x2f",
+    "mat3x2h",
+    "mat3x3",
+    "mat3x3f",
+    "mat3x3h",
+    "mat3x4",
+    "mat3x4f",
+    "mat3x4h",
+    "mat4x2",
+    "mat4x2f",
+    "mat4x2h",
+    "mat4x3",
+    "mat4x3f",
+    "mat4x3h",
+    "mat4x4",
+    "mat4x4f",
+    "mat4x4h",
+    "num_workgroups",
+    "offset",
+    "out",
+    "override",
+    "position",
+    "premerge",
+    "private",
+    "ptr",
+    "regardless",
+    "return",
+    "sample_index",
+    "sample_mask",
+    "sampler_comparison",
+    "sampler",
+    "set",
+    "storage",
+    "struct",
+    "switch",
+    "texture_1d",
+    "texture_2d_array",
+    "texture_2d",
+    "texture_3d",
+    "texture_cube_array",
+    "texture_cube",
+    "texture_depth_2d_array",
+    "texture_depth_2d",
+    "texture_depth_cube_array",
+    "texture_depth_cube",
+    "texture_depth_multisampled_2d",
+    "texture_external",
+    "texture_multisampled_2d",
+    "texture_storage_1d",
+    "texture_storage_2d_array",
+    "texture_storage_2d",
+    "texture_storage_3d",
+    "true",
+    "type",
+    "typedef",
+    "u16",
+    "u32",
+    "u64",
+    "u8",
+    "uniform_constant",
+    "uniform",
+    "unless",
+    "using",
+    "var",
+    "vec2",
+    "vec2f",
+    "vec2h",
+    "vec2i",
+    "vec2u",
+    "vec3",
+    "vec3f",
+    "vec3h",
+    "vec3i",
+    "vec3u",
+    "vec4",
+    "vec4f",
+    "vec4h",
+    "vec4i",
+    "vec4u",
+    "vertex_index",
+    "vertex",
+    "void",
+    "while",
+    "workgroup_id",
     "workgroup",
 };
 
diff --git a/src/tint/reader/spirv/parser.cc b/src/tint/reader/spirv/parser.cc
index be0d238..2a1ae18 100644
--- a/src/tint/reader/spirv/parser.cc
+++ b/src/tint/reader/spirv/parser.cc
@@ -41,7 +41,7 @@
     if (options.allow_non_uniform_derivatives) {
         // Suppress errors regarding non-uniform derivative operations if requested, by adding a
         // diagnostic directive to the module.
-        builder.DiagnosticDirective(ast::DiagnosticSeverity::kOff, "derivative_uniformity");
+        builder.DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "derivative_uniformity");
     }
 
     // The SPIR-V parser can construct disjoint AST nodes, which is invalid for
diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc
index 8a373fd..a1c9042 100644
--- a/src/tint/reader/spirv/parser_impl.cc
+++ b/src/tint/reader/spirv/parser_impl.cc
@@ -461,49 +461,42 @@
     return "SPIR-V type " + std::to_string(type_id);
 }
 
-ParserImpl::AttributeList ParserImpl::ConvertMemberDecoration(uint32_t struct_type_id,
-                                                              uint32_t member_index,
-                                                              const Type* member_ty,
-                                                              const Decoration& decoration) {
+Attributes ParserImpl::ConvertMemberDecoration(uint32_t struct_type_id,
+                                               uint32_t member_index,
+                                               const Type* member_ty,
+                                               const Decoration& decoration) {
     if (decoration.empty()) {
         Fail() << "malformed SPIR-V decoration: it's empty";
         return {};
     }
+    Attributes out;
     switch (static_cast<spv::Decoration>(decoration[0])) {
-        case spv::Decoration::Offset:
+        case spv::Decoration::Offset: {
             if (decoration.size() != 2) {
                 Fail() << "malformed Offset decoration: expected 1 literal operand, has "
                        << decoration.size() - 1 << ": member " << member_index << " of "
                        << ShowType(struct_type_id);
                 return {};
             }
-            return {
-                builder_.MemberOffset(Source{}, AInt(decoration[1])),
-            };
-        case spv::Decoration::NonReadable:
-            // WGSL doesn't have a member decoration for this.  Silently drop it.
-            return {};
-        case spv::Decoration::NonWritable:
-            // WGSL doesn't have a member decoration for this.
-            return {};
-        case spv::Decoration::ColMajor:
-            // WGSL only supports column major matrices.
-            return {};
-        case spv::Decoration::RelaxedPrecision:
-            // WGSL doesn't support relaxed precision.
-            return {};
+            out.Add(builder_.MemberOffset(Source{}, AInt(decoration[1])));
+            break;
+        }
+        case spv::Decoration::NonReadable:       // WGSL doesn't have a member decoration for this.
+        case spv::Decoration::NonWritable:       // WGSL doesn't have a member decoration for this.
+        case spv::Decoration::ColMajor:          // WGSL only supports column major matrices.
+        case spv::Decoration::RelaxedPrecision:  // WGSL doesn't support relaxed precision.
+            break;
         case spv::Decoration::RowMajor:
             Fail() << "WGSL does not support row-major matrices: can't "
                       "translate member "
                    << member_index << " of " << ShowType(struct_type_id);
-            return {};
+            break;
         case spv::Decoration::MatrixStride: {
             if (decoration.size() != 2) {
-                Fail() << "malformed MatrixStride decoration: expected 1 literal "
-                          "operand, has "
+                Fail() << "malformed MatrixStride decoration: expected 1 literal operand, has "
                        << decoration.size() - 1 << ": member " << member_index << " of "
                        << ShowType(struct_type_id);
-                return {};
+                break;
             }
             uint32_t stride = decoration[1];
             auto* ty = member_ty->UnwrapAlias();
@@ -513,31 +506,30 @@
             auto* mat = ty->As<Matrix>();
             if (!mat) {
                 Fail() << "MatrixStride cannot be applied to type " << ty->String();
-                return {};
+                break;
             }
             uint32_t natural_stride = (mat->rows == 2) ? 8 : 16;
             if (stride == natural_stride) {
-                return {};  // Decoration matches the natural stride for the matrix
+                break;  // Decoration matches the natural stride for the matrix
             }
             if (!member_ty->Is<Matrix>()) {
-                Fail() << "custom matrix strides not currently supported on array of "
-                          "matrices";
-                return {};
+                Fail() << "custom matrix strides not currently supported on array of matrices";
+                break;
             }
-            return {
-                create<ast::StrideAttribute>(Source{}, decoration[1]),
-                builder_.ASTNodes().Create<ast::DisableValidationAttribute>(
-                    builder_.ID(), builder_.AllocateNodeID(),
-                    ast::DisabledValidation::kIgnoreStrideAttribute),
-            };
-        }
-        default:
-            // TODO(dneto): Support the remaining member decorations.
+            out.Add(create<ast::StrideAttribute>(Source{}, decoration[1]));
+            out.Add(builder_.ASTNodes().Create<ast::DisableValidationAttribute>(
+                builder_.ID(), builder_.AllocateNodeID(),
+                ast::DisabledValidation::kIgnoreStrideAttribute));
             break;
+        }
+        default: {
+            // TODO(dneto): Support the remaining member decorations.
+            Fail() << "unhandled member decoration: " << decoration[0] << " on member "
+                   << member_index << " of " << ShowType(struct_type_id);
+            break;
+        }
     }
-    Fail() << "unhandled member decoration: " << decoration[0] << " on member " << member_index
-           << " of " << ShowType(struct_type_id);
-    return {};
+    return out;
 }
 
 bool ParserImpl::BuildInternalModule() {
@@ -1138,7 +1130,7 @@
         }
 
         bool is_non_writable = false;
-        AttributeList ast_member_decorations;
+        Attributes ast_member_decorations;
         for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
             if (IsPipelineDecoration(decoration)) {
                 // IO decorations are handled when emitting the entry point.
@@ -1149,11 +1141,9 @@
                 // the members are non-writable.
                 is_non_writable = true;
             } else {
-                auto decos =
+                auto attrs =
                     ConvertMemberDecoration(type_id, member_index, ast_member_ty, decoration);
-                for (auto* deco : decos) {
-                    ast_member_decorations.Push(deco);
-                }
+                ast_member_decorations.Add(attrs);
                 if (!success_) {
                     return nullptr;
                 }
@@ -1168,7 +1158,7 @@
         const auto member_name = namer_.GetMemberName(type_id, member_index);
         auto* ast_struct_member =
             builder_.Member(Source{}, member_name, ast_member_ty->Build(builder_),
-                            std::move(ast_member_decorations));
+                            std::move(ast_member_decorations.list));
         ast_members.Push(ast_struct_member);
     }
 
@@ -1222,21 +1212,16 @@
     }
 
     auto ast_address_space = enum_converter_.ToAddressSpace(storage_class);
-    if (ast_address_space == type::AddressSpace::kUndefined) {
-        Fail() << "SPIR-V pointer type with ID " << type_id << " has invalid storage class "
-               << static_cast<uint32_t>(storage_class);
-        return nullptr;
-    }
-    if (ast_address_space == type::AddressSpace::kUniform &&
+    if (ast_address_space == builtin::AddressSpace::kUniform &&
         remap_buffer_block_type_.count(pointee_type_id)) {
-        ast_address_space = type::AddressSpace::kStorage;
+        ast_address_space = builtin::AddressSpace::kStorage;
         remap_buffer_block_type_.insert(type_id);
     }
 
     // Pipeline input and output variables map to private variables.
-    if (ast_address_space == type::AddressSpace::kIn ||
-        ast_address_space == type::AddressSpace::kOut) {
-        ast_address_space = type::AddressSpace::kPrivate;
+    if (ast_address_space == builtin::AddressSpace::kIn ||
+        ast_address_space == builtin::AddressSpace::kOut) {
+        ast_address_space = builtin::AddressSpace::kPrivate;
     }
     switch (ptr_as) {
         case PtrAs::Ref:
@@ -1373,7 +1358,7 @@
                 break;
         }
         if (ast_type && ast_expr) {
-            AttributeList spec_id_decos;
+            Attributes spec_id_attrs;
             for (const auto& deco : GetDecorationsFor(inst.result_id())) {
                 if ((deco.size() == 2) && (deco[0] == uint32_t(spv::Decoration::SpecId))) {
                     const uint32_t id = deco[1];
@@ -1383,12 +1368,12 @@
                                       << inst.result_id() << " has SpecId " << id;
                     }
                     auto* cid = builder_.Id(Source{}, AInt(id));
-                    spec_id_decos.Push(cid);
+                    spec_id_attrs.Add(cid);
                     break;
                 }
             }
             auto* ast_var =
-                MakeOverride(inst.result_id(), ast_type, ast_expr, std::move(spec_id_decos));
+                MakeOverride(inst.result_id(), ast_type, ast_expr, std::move(spec_id_attrs));
             if (ast_var) {
                 scalar_spec_constants_.insert(inst.result_id());
             }
@@ -1459,14 +1444,14 @@
             continue;
         }
         switch (enum_converter_.ToAddressSpace(spirv_storage_class)) {
-            case type::AddressSpace::kNone:
-            case type::AddressSpace::kIn:
-            case type::AddressSpace::kOut:
-            case type::AddressSpace::kUniform:
-            case type::AddressSpace::kHandle:
-            case type::AddressSpace::kStorage:
-            case type::AddressSpace::kWorkgroup:
-            case type::AddressSpace::kPrivate:
+            case builtin::AddressSpace::kUndefined:
+            case builtin::AddressSpace::kIn:
+            case builtin::AddressSpace::kOut:
+            case builtin::AddressSpace::kUniform:
+            case builtin::AddressSpace::kHandle:
+            case builtin::AddressSpace::kStorage:
+            case builtin::AddressSpace::kWorkgroup:
+            case builtin::AddressSpace::kPrivate:
                 break;
             default:
                 return Fail() << "invalid SPIR-V storage class " << int(spirv_storage_class)
@@ -1476,7 +1461,7 @@
             return false;
         }
         const Type* ast_store_type = nullptr;
-        type::AddressSpace ast_address_space = type::AddressSpace::kNone;
+        builtin::AddressSpace ast_address_space = builtin::AddressSpace::kUndefined;
         if (spirv_storage_class == spv::StorageClass::UniformConstant) {
             // These are opaque handles: samplers or textures
             ast_store_type = GetHandleTypeForSpirvHandle(var);
@@ -1509,12 +1494,15 @@
             // here.)
             ast_initializer = MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
         }
-        auto* ast_var = MakeVar(var.result_id(), ast_address_space, ast_store_type, ast_initializer,
-                                utils::Empty);
+        auto ast_access = VarAccess(ast_store_type, ast_address_space);
+        auto* ast_var = MakeVar(var.result_id(), ast_address_space, ast_access, ast_store_type,
+                                ast_initializer, Attributes{});
         // TODO(dneto): initializers (a.k.a. initializer expression)
         if (ast_var) {
             builder_.AST().AddGlobalVariable(ast_var);
-            module_variable_.GetOrCreate(var.result_id(), [ast_var] { return ast_var; });
+            module_variable_.GetOrCreate(var.result_id(), [&] {
+                return ModuleVariable{ast_var, ast_address_space, ast_access};
+            });
         }
     }
 
@@ -1541,14 +1529,16 @@
                                   << init->PrettyPrint();
             }
         }
-        auto* ast_var =
-            MakeVar(builtin_position_.per_vertex_var_id,
-                    enum_converter_.ToAddressSpace(builtin_position_.storage_class),
-                    ConvertType(builtin_position_.position_member_type_id), ast_initializer, {});
+        auto storage_type = ConvertType(builtin_position_.position_member_type_id);
+        auto ast_address_space = enum_converter_.ToAddressSpace(builtin_position_.storage_class);
+        auto ast_access = VarAccess(storage_type, ast_address_space);
+        auto* ast_var = MakeVar(builtin_position_.per_vertex_var_id, ast_address_space, ast_access,
+                                storage_type, ast_initializer, {});
 
         builder_.AST().AddGlobalVariable(ast_var);
-        module_variable_.GetOrCreate(builtin_position_.per_vertex_var_id,
-                                     [ast_var] { return ast_var; });
+        module_variable_.GetOrCreate(builtin_position_.per_vertex_var_id, [&] {
+            return ModuleVariable{ast_var, ast_address_space};
+        });
     }
     return success_;
 }
@@ -1576,41 +1566,46 @@
     return size->AsIntConstant();
 }
 
+builtin::Access ParserImpl::VarAccess(const Type* storage_type,
+                                      builtin::AddressSpace address_space) {
+    if (address_space != builtin::AddressSpace::kStorage) {
+        return builtin::Access::kUndefined;
+    }
+
+    bool read_only = false;
+    if (auto* tn = storage_type->As<Named>()) {
+        read_only = read_only_struct_types_.count(tn->name) > 0;
+    }
+
+    // Apply the access(read) or access(read_write) modifier.
+    return read_only ? builtin::Access::kRead : builtin::Access::kReadWrite;
+}
+
 const ast::Var* ParserImpl::MakeVar(uint32_t id,
-                                    type::AddressSpace address_space,
+                                    builtin::AddressSpace address_space,
+                                    builtin::Access access,
                                     const Type* storage_type,
                                     const ast::Expression* initializer,
-                                    AttributeList decorations) {
+                                    Attributes attrs) {
     if (storage_type == nullptr) {
         Fail() << "internal error: can't make ast::Variable for null type";
         return nullptr;
     }
 
-    type::Access access = type::Access::kUndefined;
-    if (address_space == type::AddressSpace::kStorage) {
-        bool read_only = false;
-        if (auto* tn = storage_type->As<Named>()) {
-            read_only = read_only_struct_types_.count(tn->name) > 0;
-        }
-
-        // Apply the access(read) or access(read_write) modifier.
-        access = read_only ? type::Access::kRead : type::Access::kReadWrite;
-    }
-
     // Handle variables (textures and samplers) are always in the handle
     // address space, so we don't mention the address space.
-    if (address_space == type::AddressSpace::kHandle) {
-        address_space = type::AddressSpace::kNone;
+    if (address_space == builtin::AddressSpace::kHandle) {
+        address_space = builtin::AddressSpace::kUndefined;
     }
 
-    if (!ConvertDecorationsForVariable(id, &storage_type, &decorations,
-                                       address_space != type::AddressSpace::kPrivate)) {
+    if (!ConvertDecorationsForVariable(id, &storage_type, attrs,
+                                       address_space != builtin::AddressSpace::kPrivate)) {
         return nullptr;
     }
 
     auto sym = builder_.Symbols().Register(namer_.Name(id));
     return builder_.Var(Source{}, sym, storage_type->Build(builder_), address_space, access,
-                        initializer, decorations);
+                        initializer, std::move(attrs.list));
 }
 
 const ast::Let* ParserImpl::MakeLet(uint32_t id,
@@ -1623,28 +1618,27 @@
 const ast::Override* ParserImpl::MakeOverride(uint32_t id,
                                               const Type* type,
                                               const ast::Expression* initializer,
-                                              AttributeList decorations) {
-    if (!ConvertDecorationsForVariable(id, &type, &decorations, false)) {
+                                              Attributes attrs) {
+    if (!ConvertDecorationsForVariable(id, &type, attrs, false)) {
         return nullptr;
     }
     auto sym = builder_.Symbols().Register(namer_.Name(id));
-    return builder_.Override(Source{}, sym, type->Build(builder_), initializer, decorations);
+    return builder_.Override(Source{}, sym, type->Build(builder_), initializer,
+                             std::move(attrs.list));
 }
 
-const ast::Parameter* ParserImpl::MakeParameter(uint32_t id,
-                                                const Type* type,
-                                                AttributeList decorations) {
-    if (!ConvertDecorationsForVariable(id, &type, &decorations, false)) {
+const ast::Parameter* ParserImpl::MakeParameter(uint32_t id, const Type* type, Attributes attrs) {
+    if (!ConvertDecorationsForVariable(id, &type, attrs, false)) {
         return nullptr;
     }
 
     auto sym = builder_.Symbols().Register(namer_.Name(id));
-    return builder_.Param(Source{}, sym, type->Build(builder_), decorations);
+    return builder_.Param(Source{}, sym, type->Build(builder_), attrs.list);
 }
 
 bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
                                                const Type** store_type,
-                                               AttributeList* decorations,
+                                               Attributes& attrs,
                                                bool transfer_pipeline_io) {
     DecorationList non_builtin_pipeline_decorations;
     for (auto& deco : GetDecorationsFor(id)) {
@@ -1704,7 +1698,7 @@
                 return false;
             }
             if (transfer_pipeline_io) {
-                decorations->Push(create<ast::BuiltinAttribute>(Source{}, ast_builtin));
+                attrs.Add(builder_, Source{}, ast_builtin);
             }
         }
         if (transfer_pipeline_io && IsPipelineDecoration(deco)) {
@@ -1715,19 +1709,18 @@
                 return Fail() << "malformed DescriptorSet decoration on ID " << id
                               << ": has no operand";
             }
-            decorations->Push(builder_.Group(Source{}, AInt(deco[1])));
+            attrs.Add(builder_.Group(Source{}, AInt(deco[1])));
         }
         if (deco[0] == uint32_t(spv::Decoration::Binding)) {
             if (deco.size() == 1) {
                 return Fail() << "malformed Binding decoration on ID " << id << ": has no operand";
             }
-            decorations->Push(builder_.Binding(Source{}, AInt(deco[1])));
+            attrs.Add(builder_.Binding(Source{}, AInt(deco[1])));
         }
     }
 
     if (transfer_pipeline_io) {
-        if (!ConvertPipelineDecorations(*store_type, non_builtin_pipeline_decorations,
-                                        decorations)) {
+        if (!ConvertPipelineDecorations(*store_type, non_builtin_pipeline_decorations, attrs)) {
             return false;
         }
     }
@@ -1748,11 +1741,11 @@
     return result;
 }
 
-void ParserImpl::SetLocation(AttributeList* attributes, const ast::Attribute* replacement) {
+void ParserImpl::SetLocation(Attributes& attributes, const ast::Attribute* replacement) {
     if (!replacement) {
         return;
     }
-    for (auto*& attribute : *attributes) {
+    for (auto*& attribute : attributes.list) {
         if (attribute->Is<ast::LocationAttribute>()) {
             // Replace this location attribute with the replacement.
             // The old one doesn't leak because it's kept in the builder's AST node
@@ -1762,74 +1755,73 @@
         }
     }
     // The list didn't have a location. Add it.
-    attributes->Push(replacement);
+    attributes.Add(replacement);
     return;
 }
 
 bool ParserImpl::ConvertPipelineDecorations(const Type* store_type,
                                             const DecorationList& decorations,
-                                            AttributeList* attributes) {
+                                            Attributes& attributes) {
     // Vulkan defaults to perspective-correct interpolation.
-    ast::InterpolationType type = ast::InterpolationType::kPerspective;
-    ast::InterpolationSampling sampling = ast::InterpolationSampling::kUndefined;
+    builtin::InterpolationType type = builtin::InterpolationType::kPerspective;
+    builtin::InterpolationSampling sampling = builtin::InterpolationSampling::kUndefined;
 
     for (const auto& deco : decorations) {
         TINT_ASSERT(Reader, deco.size() > 0);
         switch (static_cast<spv::Decoration>(deco[0])) {
             case spv::Decoration::Location:
                 if (deco.size() != 2) {
-                    return Fail() << "malformed Location decoration on ID requires one "
-                                     "literal operand";
+                    return Fail()
+                           << "malformed Location decoration on ID requires one literal operand";
                 }
                 SetLocation(attributes, builder_.Location(AInt(deco[1])));
                 if (store_type->IsIntegerScalarOrVector()) {
                     // Default to flat interpolation for integral user-defined IO types.
-                    type = ast::InterpolationType::kFlat;
+                    type = builtin::InterpolationType::kFlat;
                 }
                 break;
             case spv::Decoration::Flat:
-                type = ast::InterpolationType::kFlat;
+                type = builtin::InterpolationType::kFlat;
                 break;
             case spv::Decoration::NoPerspective:
                 if (store_type->IsIntegerScalarOrVector()) {
                     // This doesn't capture the array or struct case.
                     return Fail() << "NoPerspective is invalid on integral IO";
                 }
-                type = ast::InterpolationType::kLinear;
+                type = builtin::InterpolationType::kLinear;
                 break;
             case spv::Decoration::Centroid:
                 if (store_type->IsIntegerScalarOrVector()) {
                     // This doesn't capture the array or struct case.
                     return Fail() << "Centroid interpolation sampling is invalid on integral IO";
                 }
-                sampling = ast::InterpolationSampling::kCentroid;
+                sampling = builtin::InterpolationSampling::kCentroid;
                 break;
             case spv::Decoration::Sample:
                 if (store_type->IsIntegerScalarOrVector()) {
                     // This doesn't capture the array or struct case.
                     return Fail() << "Sample interpolation sampling is invalid on integral IO";
                 }
-                sampling = ast::InterpolationSampling::kSample;
+                sampling = builtin::InterpolationSampling::kSample;
                 break;
             default:
                 break;
         }
     }
 
-    if (type == ast::InterpolationType::kFlat &&
-        !ast::HasAttribute<ast::LocationAttribute>(*attributes)) {
+    if (type == builtin::InterpolationType::kFlat && !attributes.Has<ast::LocationAttribute>()) {
         // WGSL requires that '@interpolate(flat)' needs to be paired with '@location', however
         // SPIR-V requires all fragment shader integer Inputs are 'flat'. If the decorations do not
         // contain a spv::Decoration::Location, then make this perspective.
-        type = ast::InterpolationType::kPerspective;
+        type = builtin::InterpolationType::kPerspective;
     }
 
     // Apply interpolation.
-    if (type == ast::InterpolationType::kPerspective &&
-        sampling == ast::InterpolationSampling::kUndefined) {
+    if (type == builtin::InterpolationType::kPerspective &&
+        sampling == builtin::InterpolationSampling::kUndefined) {
         // This is the default. Don't add a decoration.
     } else {
-        attributes->Push(create<ast::InterpolateAttribute>(type, sampling));
+        attributes.Add(builder_.Interpolate(type, sampling));
     }
 
     return success();
@@ -2522,9 +2514,9 @@
                 ast_handle_type = ty_.SampledTexture(dim, ast_sampled_component_type);
             }
         } else {
-            const auto access = type::Access::kWrite;
+            const auto access = builtin::Access::kWrite;
             const auto format = enum_converter_.ToTexelFormat(image_type->format());
-            if (format == type::TexelFormat::kUndefined) {
+            if (format == builtin::TexelFormat::kUndefined) {
                 return nullptr;
             }
             ast_handle_type = ty_.StorageTexture(dim, format, access);
@@ -2541,28 +2533,28 @@
     return ast_handle_type;
 }
 
-const Type* ParserImpl::GetComponentTypeForFormat(type::TexelFormat format) {
+const Type* ParserImpl::GetComponentTypeForFormat(builtin::TexelFormat format) {
     switch (format) {
-        case type::TexelFormat::kR32Uint:
-        case type::TexelFormat::kRgba8Uint:
-        case type::TexelFormat::kRg32Uint:
-        case type::TexelFormat::kRgba16Uint:
-        case type::TexelFormat::kRgba32Uint:
+        case builtin::TexelFormat::kR32Uint:
+        case builtin::TexelFormat::kRgba8Uint:
+        case builtin::TexelFormat::kRg32Uint:
+        case builtin::TexelFormat::kRgba16Uint:
+        case builtin::TexelFormat::kRgba32Uint:
             return ty_.U32();
 
-        case type::TexelFormat::kR32Sint:
-        case type::TexelFormat::kRgba8Sint:
-        case type::TexelFormat::kRg32Sint:
-        case type::TexelFormat::kRgba16Sint:
-        case type::TexelFormat::kRgba32Sint:
+        case builtin::TexelFormat::kR32Sint:
+        case builtin::TexelFormat::kRgba8Sint:
+        case builtin::TexelFormat::kRg32Sint:
+        case builtin::TexelFormat::kRgba16Sint:
+        case builtin::TexelFormat::kRgba32Sint:
             return ty_.I32();
 
-        case type::TexelFormat::kRgba8Unorm:
-        case type::TexelFormat::kRgba8Snorm:
-        case type::TexelFormat::kR32Float:
-        case type::TexelFormat::kRg32Float:
-        case type::TexelFormat::kRgba16Float:
-        case type::TexelFormat::kRgba32Float:
+        case builtin::TexelFormat::kRgba8Unorm:
+        case builtin::TexelFormat::kRgba8Snorm:
+        case builtin::TexelFormat::kR32Float:
+        case builtin::TexelFormat::kRg32Float:
+        case builtin::TexelFormat::kRgba16Float:
+        case builtin::TexelFormat::kRgba32Float:
             return ty_.F32();
         default:
             break;
@@ -2571,30 +2563,30 @@
     return nullptr;
 }
 
-unsigned ParserImpl::GetChannelCountForFormat(type::TexelFormat format) {
+unsigned ParserImpl::GetChannelCountForFormat(builtin::TexelFormat format) {
     switch (format) {
-        case type::TexelFormat::kR32Float:
-        case type::TexelFormat::kR32Sint:
-        case type::TexelFormat::kR32Uint:
+        case builtin::TexelFormat::kR32Float:
+        case builtin::TexelFormat::kR32Sint:
+        case builtin::TexelFormat::kR32Uint:
             // One channel
             return 1;
 
-        case type::TexelFormat::kRg32Float:
-        case type::TexelFormat::kRg32Sint:
-        case type::TexelFormat::kRg32Uint:
+        case builtin::TexelFormat::kRg32Float:
+        case builtin::TexelFormat::kRg32Sint:
+        case builtin::TexelFormat::kRg32Uint:
             // Two channels
             return 2;
 
-        case type::TexelFormat::kRgba16Float:
-        case type::TexelFormat::kRgba16Sint:
-        case type::TexelFormat::kRgba16Uint:
-        case type::TexelFormat::kRgba32Float:
-        case type::TexelFormat::kRgba32Sint:
-        case type::TexelFormat::kRgba32Uint:
-        case type::TexelFormat::kRgba8Sint:
-        case type::TexelFormat::kRgba8Snorm:
-        case type::TexelFormat::kRgba8Uint:
-        case type::TexelFormat::kRgba8Unorm:
+        case builtin::TexelFormat::kRgba16Float:
+        case builtin::TexelFormat::kRgba16Sint:
+        case builtin::TexelFormat::kRgba16Uint:
+        case builtin::TexelFormat::kRgba32Float:
+        case builtin::TexelFormat::kRgba32Sint:
+        case builtin::TexelFormat::kRgba32Uint:
+        case builtin::TexelFormat::kRgba8Sint:
+        case builtin::TexelFormat::kRgba8Snorm:
+        case builtin::TexelFormat::kRgba8Uint:
+        case builtin::TexelFormat::kRgba8Unorm:
             // Four channels
             return 4;
 
@@ -2605,7 +2597,7 @@
     return 0;
 }
 
-const Type* ParserImpl::GetTexelTypeForFormat(type::TexelFormat format) {
+const Type* ParserImpl::GetTexelTypeForFormat(builtin::TexelFormat format) {
     const auto* component_type = GetComponentTypeForFormat(format);
     if (!component_type) {
         return nullptr;
diff --git a/src/tint/reader/spirv/parser_impl.h b/src/tint/reader/spirv/parser_impl.h
index 1e64866..36c24de 100644
--- a/src/tint/reader/spirv/parser_impl.h
+++ b/src/tint/reader/spirv/parser_impl.h
@@ -37,6 +37,7 @@
 
 #include "src/tint/program_builder.h"
 #include "src/tint/reader/reader.h"
+#include "src/tint/reader/spirv/attributes.h"
 #include "src/tint/reader/spirv/entry_point_info.h"
 #include "src/tint/reader/spirv/enum_converter.h"
 #include "src/tint/reader/spirv/namer.h"
@@ -122,7 +123,6 @@
 
 /// Parser implementation for SPIR-V.
 class ParserImpl : Reader {
-    using AttributeList = utils::Vector<const ast::Attribute*, 8>;
     using ExpressionList = utils::Vector<const ast::Expression*, 8>;
 
   public:
@@ -261,7 +261,7 @@
     /// @returns false when the variable should not be emitted as a variable
     bool ConvertDecorationsForVariable(uint32_t id,
                                        const Type** store_type,
-                                       AttributeList* attributes,
+                                       Attributes& attributes,
                                        bool transfer_pipeline_io);
 
     /// Converts SPIR-V decorations for pipeline IO into AST decorations.
@@ -271,15 +271,15 @@
     /// @returns false if conversion fails
     bool ConvertPipelineDecorations(const Type* store_type,
                                     const DecorationList& decorations,
-                                    AttributeList* attributes);
+                                    Attributes& attributes);
 
     /// Updates the attribute list, placing a non-null location decoration into
     /// the list, replacing an existing one if it exists. Does nothing if the
     /// replacement is nullptr.
     /// Assumes the list contains at most one Location decoration.
-    /// @param decos the attribute list to modify
+    /// @param attributes the attribute list to modify
     /// @param replacement the location decoration to place into the list
-    void SetLocation(AttributeList* decos, const ast::Attribute* replacement);
+    void SetLocation(Attributes& attributes, const ast::Attribute* replacement);
 
     /// Converts a SPIR-V struct member decoration into a number of AST
     /// decorations. If the decoration is recognized but deliberately dropped,
@@ -290,10 +290,10 @@
     /// @param member_ty the type of the member
     /// @param decoration an encoded SPIR-V Decoration
     /// @returns the AST decorations
-    AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
-                                          uint32_t member_index,
-                                          const Type* member_ty,
-                                          const Decoration& decoration);
+    Attributes ConvertMemberDecoration(uint32_t struct_type_id,
+                                       uint32_t member_index,
+                                       const Type* member_ty,
+                                       const Decoration& decoration);
 
     /// Returns a string for the given type.  If the type ID is invalid,
     /// then the resulting string only names the type ID.
@@ -420,20 +420,28 @@
     /// @returns a list of SPIR-V decorations.
     DecorationList GetMemberPipelineDecorations(const Struct& struct_type, int member_index);
 
+    /// @param storage_type the 'var' storage type
+    /// @param address_space the 'var' address space
+    /// @returns the access mode for a 'var' declaration with the given storage type and address
+    /// space.
+    builtin::Access VarAccess(const Type* storage_type, builtin::AddressSpace address_space);
+
     /// Creates an AST 'var' node for a SPIR-V ID, including any attached decorations, unless it's
     /// an ignorable builtin variable.
     /// @param id the SPIR-V result ID
-    /// @param address_space the address space, which cannot be type::AddressSpace::kNone
+    /// @param address_space the address space, which cannot be builtin::AddressSpace::kUndefined
+    /// @param access the access
     /// @param storage_type the storage type of the variable
     /// @param initializer the variable initializer
-    /// @param decorations the variable decorations
+    /// @param attributes the variable attributes
     /// @returns a new Variable node, or null in the ignorable variable case and
     /// in the error case
     const ast::Var* MakeVar(uint32_t id,
-                            type::AddressSpace address_space,
+                            builtin::AddressSpace address_space,
+                            builtin::Access access,
                             const Type* storage_type,
                             const ast::Expression* initializer,
-                            AttributeList decorations);
+                            Attributes attributes);
 
     /// Creates an AST 'let' node for a SPIR-V ID, including any attached decorations,.
     /// @param id the SPIR-V result ID
@@ -446,20 +454,20 @@
     /// @param id the SPIR-V result ID
     /// @param type the type of the variable
     /// @param initializer the variable initializer
-    /// @param decorations the variable decorations
+    /// @param attributes the variable attributes
     /// @returns the AST 'override' node
     const ast::Override* MakeOverride(uint32_t id,
                                       const Type* type,
                                       const ast::Expression* initializer,
-                                      AttributeList decorations);
+                                      Attributes attributes);
 
     /// Creates an AST parameter node for a SPIR-V ID, including any attached decorations, unless
     /// it's an ignorable builtin variable.
     /// @param id the SPIR-V result ID
     /// @param type the type of the parameter
-    /// @param decorations the parameter decorations
+    /// @param attributes the parameter attributes
     /// @returns the AST parameter node
-    const ast::Parameter* MakeParameter(uint32_t id, const Type* type, AttributeList decorations);
+    const ast::Parameter* MakeParameter(uint32_t id, const Type* type, Attributes attributes);
 
     /// Returns true if a constant expression can be generated.
     /// @param id the SPIR-V ID of the value
@@ -659,32 +667,42 @@
     /// error
     const Type* GetHandleTypeForSpirvHandle(const spvtools::opt::Instruction& obj);
 
+    /// ModuleVariable describes a module scope variable
+    struct ModuleVariable {
+        /// The AST variable node.
+        const ast::Var* var = nullptr;
+        /// The address space of the var
+        builtin::AddressSpace address_space = builtin::AddressSpace::kUndefined;
+        /// The access mode of the var
+        builtin::Access access = builtin::Access::kUndefined;
+    };
+
     /// Returns the AST variable for the SPIR-V ID of a module-scope variable,
     /// or null if there isn't one.
     /// @param id a SPIR-V ID
     /// @returns the AST variable or null.
-    const ast::Var* GetModuleVariable(uint32_t id) {
+    ModuleVariable GetModuleVariable(uint32_t id) {
         auto entry = module_variable_.Find(id);
-        return entry ? *entry : nullptr;
+        return entry ? *entry : ModuleVariable{};
     }
 
     /// Returns the channel component type corresponding to the given image
     /// format.
     /// @param format image texel format
     /// @returns the component type, one of f32, i32, u32
-    const Type* GetComponentTypeForFormat(type::TexelFormat format);
+    const Type* GetComponentTypeForFormat(builtin::TexelFormat format);
 
     /// Returns the number of channels in the given image format.
     /// @param format image texel format
     /// @returns the number of channels in the format
-    unsigned GetChannelCountForFormat(type::TexelFormat format);
+    unsigned GetChannelCountForFormat(builtin::TexelFormat format);
 
     /// Returns the texel type corresponding to the given image format.
     /// This the WGSL type used for the texel parameter to textureStore.
     /// It's always a 4-element vector.
     /// @param format image texel format
     /// @returns the texel format
-    const Type* GetTexelTypeForFormat(type::TexelFormat format);
+    const Type* GetTexelTypeForFormat(builtin::TexelFormat format);
 
     /// Returns the SPIR-V instruction with the given ID, or nullptr.
     /// @param id the SPIR-V result ID
@@ -885,7 +903,7 @@
     std::unordered_map<const spvtools::opt::Instruction*, const Type*> handle_type_;
 
     /// Maps the SPIR-V ID of a module-scope variable to its AST variable.
-    utils::Hashmap<uint32_t, const ast::Var*, 16> module_variable_;
+    utils::Hashmap<uint32_t, ModuleVariable, 16> module_variable_;
 
     // Set of symbols of declared type that have been added, used to avoid
     // adding duplicates.
diff --git a/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc b/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
index 402cc41..d67ccf0 100644
--- a/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
+++ b/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
@@ -24,7 +24,7 @@
     auto p = parser(std::vector<uint32_t>{});
 
     auto result = p->ConvertMemberDecoration(1, 1, nullptr, {});
-    EXPECT_TRUE(result.IsEmpty());
+    EXPECT_TRUE(result.list.IsEmpty());
     EXPECT_THAT(p->error(), Eq("malformed SPIR-V decoration: it's empty"));
 }
 
@@ -32,7 +32,7 @@
     auto p = parser(std::vector<uint32_t>{});
 
     auto result = p->ConvertMemberDecoration(12, 13, nullptr, {uint32_t(spv::Decoration::Offset)});
-    EXPECT_TRUE(result.IsEmpty());
+    EXPECT_TRUE(result.list.IsEmpty());
     EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
                                "operand, has 0: member 13 of SPIR-V type 12"));
 }
@@ -42,7 +42,7 @@
 
     auto result =
         p->ConvertMemberDecoration(12, 13, nullptr, {uint32_t(spv::Decoration::Offset), 3, 4});
-    EXPECT_TRUE(result.IsEmpty());
+    EXPECT_TRUE(result.list.IsEmpty());
     EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
                                "operand, has 2: member 13 of SPIR-V type 12"));
 }
@@ -51,9 +51,9 @@
     auto p = parser(std::vector<uint32_t>{});
 
     auto result = p->ConvertMemberDecoration(1, 1, nullptr, {uint32_t(spv::Decoration::Offset), 8});
-    ASSERT_FALSE(result.IsEmpty());
-    EXPECT_TRUE(result[0]->Is<ast::StructMemberOffsetAttribute>());
-    auto* offset_deco = result[0]->As<ast::StructMemberOffsetAttribute>();
+    ASSERT_FALSE(result.list.IsEmpty());
+    EXPECT_TRUE(result.list[0]->Is<ast::StructMemberOffsetAttribute>());
+    auto* offset_deco = result.list[0]->As<ast::StructMemberOffsetAttribute>();
     ASSERT_NE(offset_deco, nullptr);
     ASSERT_TRUE(offset_deco->expr->Is<ast::IntLiteralExpression>());
     EXPECT_EQ(offset_deco->expr->As<ast::IntLiteralExpression>()->value, 8u);
@@ -67,7 +67,7 @@
     spirv::Matrix matrix(&f32, 2, 2);
     auto result =
         p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 8});
-    EXPECT_TRUE(result.IsEmpty());
+    EXPECT_TRUE(result.list.IsEmpty());
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -78,9 +78,9 @@
     spirv::Matrix matrix(&f32, 2, 2);
     auto result =
         p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 16});
-    ASSERT_FALSE(result.IsEmpty());
-    EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
-    auto* stride_deco = result[0]->As<ast::StrideAttribute>();
+    ASSERT_FALSE(result.list.IsEmpty());
+    EXPECT_TRUE(result.list[0]->Is<ast::StrideAttribute>());
+    auto* stride_deco = result.list[0]->As<ast::StrideAttribute>();
     ASSERT_NE(stride_deco, nullptr);
     EXPECT_EQ(stride_deco->stride, 16u);
     EXPECT_TRUE(p->error().empty());
@@ -93,7 +93,7 @@
     spirv::Matrix matrix(&f32, 2, 4);
     auto result =
         p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 16});
-    EXPECT_TRUE(result.IsEmpty());
+    EXPECT_TRUE(result.list.IsEmpty());
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -104,9 +104,9 @@
     spirv::Matrix matrix(&f32, 2, 4);
     auto result =
         p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 64});
-    ASSERT_FALSE(result.IsEmpty());
-    EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
-    auto* stride_deco = result[0]->As<ast::StrideAttribute>();
+    ASSERT_FALSE(result.list.IsEmpty());
+    EXPECT_TRUE(result.list[0]->Is<ast::StrideAttribute>());
+    auto* stride_deco = result.list[0]->As<ast::StrideAttribute>();
     ASSERT_NE(stride_deco, nullptr);
     EXPECT_EQ(stride_deco->stride, 64u);
     EXPECT_TRUE(p->error().empty());
@@ -119,9 +119,9 @@
     spirv::Matrix matrix(&f32, 2, 3);
     auto result =
         p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 32});
-    ASSERT_FALSE(result.IsEmpty());
-    EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
-    auto* stride_deco = result[0]->As<ast::StrideAttribute>();
+    ASSERT_FALSE(result.list.IsEmpty());
+    EXPECT_TRUE(result.list[0]->Is<ast::StrideAttribute>());
+    auto* stride_deco = result.list[0]->As<ast::StrideAttribute>();
     ASSERT_NE(stride_deco, nullptr);
     EXPECT_EQ(stride_deco->stride, 32u);
     EXPECT_TRUE(p->error().empty());
@@ -135,7 +135,7 @@
 
     auto result =
         p->ConvertMemberDecoration(1, 1, nullptr, {uint32_t(spv::Decoration::RelaxedPrecision)});
-    EXPECT_TRUE(result.IsEmpty());
+    EXPECT_TRUE(result.list.IsEmpty());
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -143,7 +143,7 @@
     auto p = parser(std::vector<uint32_t>{});
 
     auto result = p->ConvertMemberDecoration(12, 13, nullptr, {12345678});
-    EXPECT_TRUE(result.IsEmpty());
+    EXPECT_TRUE(result.list.IsEmpty());
     EXPECT_THAT(p->error(), Eq("unhandled member decoration: 12345678 on member "
                                "13 of SPIR-V type 12"));
 }
diff --git a/src/tint/reader/spirv/parser_impl_convert_type_test.cc b/src/tint/reader/spirv/parser_impl_convert_type_test.cc
index 0dc8ddc..fd9a406 100644
--- a/src/tint/reader/spirv/parser_impl_convert_type_test.cc
+++ b/src/tint/reader/spirv/parser_impl_convert_type_test.cc
@@ -731,7 +731,7 @@
     auto* ptr_ty = type->As<Pointer>();
     EXPECT_NE(ptr_ty, nullptr);
     EXPECT_TRUE(ptr_ty->type->Is<F32>());
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kPrivate);
+    EXPECT_EQ(ptr_ty->address_space, builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -747,7 +747,7 @@
     auto* ptr_ty = type->As<Pointer>();
     EXPECT_NE(ptr_ty, nullptr);
     EXPECT_TRUE(ptr_ty->type->Is<F32>());
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kPrivate);
+    EXPECT_EQ(ptr_ty->address_space, builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -763,7 +763,7 @@
     auto* ptr_ty = type->As<Pointer>();
     EXPECT_NE(ptr_ty, nullptr);
     EXPECT_TRUE(ptr_ty->type->Is<F32>());
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kUniform);
+    EXPECT_EQ(ptr_ty->address_space, builtin::AddressSpace::kUniform);
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -779,23 +779,7 @@
     auto* ptr_ty = type->As<Pointer>();
     EXPECT_NE(ptr_ty, nullptr);
     EXPECT_TRUE(ptr_ty->type->Is<F32>());
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kWorkgroup);
-    EXPECT_TRUE(p->error().empty());
-}
-
-TEST_F(SpvParserTest, ConvertType_PointerUniformConstant) {
-    auto p = parser(test::Assemble(Preamble() + R"(
-  %float = OpTypeFloat 32
-  %3 = OpTypePointer UniformConstant %float
-  )" + MainBody()));
-    EXPECT_TRUE(p->BuildInternalModule());
-
-    auto* type = p->ConvertType(3);
-    EXPECT_TRUE(type->Is<Pointer>());
-    auto* ptr_ty = type->As<Pointer>();
-    EXPECT_NE(ptr_ty, nullptr);
-    EXPECT_TRUE(ptr_ty->type->Is<F32>());
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kNone);
+    EXPECT_EQ(ptr_ty->address_space, builtin::AddressSpace::kWorkgroup);
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -811,7 +795,7 @@
     auto* ptr_ty = type->As<Pointer>();
     EXPECT_NE(ptr_ty, nullptr);
     EXPECT_TRUE(ptr_ty->type->Is<F32>());
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kStorage);
+    EXPECT_EQ(ptr_ty->address_space, builtin::AddressSpace::kStorage);
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -827,7 +811,7 @@
     auto* ptr_ty = type->As<Pointer>();
     EXPECT_NE(ptr_ty, nullptr);
     EXPECT_TRUE(ptr_ty->type->Is<F32>());
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kPrivate);
+    EXPECT_EQ(ptr_ty->address_space, builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -843,7 +827,7 @@
     auto* ptr_ty = type->As<Pointer>();
     EXPECT_NE(ptr_ty, nullptr);
     EXPECT_TRUE(ptr_ty->type->Is<F32>());
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kFunction);
+    EXPECT_EQ(ptr_ty->address_space, builtin::AddressSpace::kFunction);
     EXPECT_TRUE(p->error().empty());
 }
 
@@ -862,12 +846,12 @@
 
     auto* ptr_ty = type->As<Pointer>();
     EXPECT_NE(ptr_ty, nullptr);
-    EXPECT_EQ(ptr_ty->address_space, type::AddressSpace::kPrivate);
+    EXPECT_EQ(ptr_ty->address_space, builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(ptr_ty->type->Is<Pointer>());
 
     auto* ptr_ptr_ty = ptr_ty->type->As<Pointer>();
     EXPECT_NE(ptr_ptr_ty, nullptr);
-    EXPECT_EQ(ptr_ptr_ty->address_space, type::AddressSpace::kPrivate);
+    EXPECT_EQ(ptr_ptr_ty->address_space, builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(ptr_ptr_ty->type->Is<F32>());
 
     EXPECT_TRUE(p->error().empty());
diff --git a/src/tint/reader/spirv/parser_impl_get_decorations_test.cc b/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
index cbc384f..43e6e2d 100644
--- a/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
+++ b/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
@@ -28,7 +28,7 @@
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_NotAnId) {
     auto p = parser(test::Assemble(""));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsFor(42);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
@@ -37,7 +37,7 @@
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_NoDecorations) {
     auto p = parser(test::Assemble("%1 = OpTypeVoid"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsFor(1);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
@@ -50,7 +50,7 @@
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsFor(10);
     EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::Block)}));
     EXPECT_TRUE(p->error().empty());
@@ -64,7 +64,7 @@
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsFor(10);
     EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::Block)}));
     EXPECT_TRUE(p->error().empty());
@@ -78,7 +78,7 @@
     %float = OpTypeFloat 32
     %5 = OpConstant %float 3.14
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsFor(5);
     EXPECT_THAT(decorations,
                 UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::RelaxedPrecision)},
@@ -89,7 +89,7 @@
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_NotAnId) {
     auto p = parser(test::Assemble(""));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsForMember(42, 9);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
@@ -98,7 +98,7 @@
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_NotAStruct) {
     auto p = parser(test::Assemble("%1 = OpTypeVoid"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsFor(1);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
@@ -110,7 +110,7 @@
     %uint = OpTypeInt 32 0
     %10 = OpTypeStruct %uint
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsForMember(10, 0);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
@@ -123,7 +123,7 @@
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
     auto decorations = p->GetDecorationsForMember(10, 0);
     EXPECT_THAT(decorations,
                 UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::RelaxedPrecision)}));
@@ -138,7 +138,7 @@
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
     auto decorations = p->GetDecorationsForMember(10, 0);
     EXPECT_THAT(decorations,
                 UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::RelaxedPrecision)}));
@@ -155,7 +155,7 @@
     %arr = OpTypeArray %uint %uint_2
     %10 = OpTypeStruct %uint %arr
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
     auto decorations = p->GetDecorationsForMember(10, 1);
     EXPECT_THAT(decorations,
                 UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::ArrayStride), 12}));
@@ -179,7 +179,7 @@
     %arr = OpTypeArray %mat %uint_2
     %50 = OpTypeStruct %uint %float %arr
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
 
     EXPECT_TRUE(p->GetDecorationsForMember(50, 0).empty());
     EXPECT_THAT(p->GetDecorationsForMember(50, 1),
@@ -199,7 +199,7 @@
     %ptr = OpTypePointer Workgroup %float
     %10 = OpVariable %ptr Workgroup
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsFor(10);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
@@ -215,7 +215,7 @@
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
     auto decorations = p->GetDecorationsForMember(10, 0);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
@@ -230,7 +230,7 @@
     %ptr = OpTypePointer Workgroup %float
     %10 = OpVariable %ptr Workgroup
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
     auto decorations = p->GetDecorationsFor(10);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
@@ -246,7 +246,7 @@
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
     auto decorations = p->GetDecorationsFor(10);
     EXPECT_TRUE(decorations.empty());
     EXPECT_TRUE(p->error().empty());
diff --git a/src/tint/reader/spirv/parser_impl_handle_test.cc b/src/tint/reader/spirv/parser_impl_handle_test.cc
index fbf73e4..2413386 100644
--- a/src/tint/reader/spirv/parser_impl_handle_test.cc
+++ b/src/tint/reader/spirv/parser_impl_handle_test.cc
@@ -2937,7 +2937,7 @@
 
 INSTANTIATE_TEST_SUITE_P(
     // When SPIR-V wants the result type to be unsigned, we have to
-    // insert a type initializer or bitcast for WGSL to do the type
+    // insert a value constructor or bitcast for WGSL to do the type
     // coercion. But the algorithm already does that as a matter
     // of course.
     ImageQuerySizeLod_NonArrayed_UnsignedResult_SignedLevel,
@@ -3002,8 +3002,7 @@
                               R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    // Spot check that a type conversion is inserted when SPIR-V asks for
-    // an unsigned int result.
+    // Spot check that a value conversion is inserted when SPIR-V asks for an unsigned int result.
     ImageQueryLevels_UnsignedResult,
     SpvParserHandleTest_SampledImageAccessTest,
     ::testing::ValuesIn(std::vector<ImageAccessCase>{
@@ -3886,7 +3885,6 @@
            OpFunctionEnd
   )";
     auto p = parser(test::Assemble(assembly));
-    std::cout << assembly;
     EXPECT_TRUE(p->BuildAndParseInternalModule()) << assembly;
     auto fe = p->function_emitter(100);
     EXPECT_TRUE(fe.EmitBody()) << p->error();
diff --git a/src/tint/reader/spirv/parser_impl_module_var_test.cc b/src/tint/reader/spirv/parser_impl_module_var_test.cc
index 5077a51..c731fbf 100644
--- a/src/tint/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/tint/reader/spirv/parser_impl_module_var_test.cc
@@ -2861,7 +2861,7 @@
     const auto module_str = test::ToString(p->program());
     const std::string expected = R"(var<private> x_1 : i32;
 
-var<private> position : vec4<f32>;
+var<private> position_1 : vec4<f32>;
 
 fn main_1() {
   let x_2 : i32 = x_1;
@@ -2870,14 +2870,14 @@
 
 struct main_out {
   @builtin(position)
-  position_1 : vec4<f32>,
+  position_1_1 : vec4<f32>,
 }
 
 @vertex
 fn main(@builtin(instance_index) x_1_param : u32) -> main_out {
   x_1 = bitcast<i32>(x_1_param);
   main_1();
-  return main_out(position);
+  return main_out(position_1);
 }
 )";
     EXPECT_EQ(module_str, expected) << module_str;
@@ -2898,7 +2898,7 @@
     const auto module_str = test::ToString(p->program());
     const std::string expected = R"(var<private> x_1 : i32;
 
-var<private> position : vec4<f32>;
+var<private> position_1 : vec4<f32>;
 
 fn main_1() {
   let x_14 : ptr<private, i32> = &(x_1);
@@ -2908,14 +2908,14 @@
 
 struct main_out {
   @builtin(position)
-  position_1 : vec4<f32>,
+  position_1_1 : vec4<f32>,
 }
 
 @vertex
 fn main(@builtin(instance_index) x_1_param : u32) -> main_out {
   x_1 = bitcast<i32>(x_1_param);
   main_1();
-  return main_out(position);
+  return main_out(position_1);
 }
 )";
     EXPECT_EQ(module_str, expected) << module_str;
@@ -2936,7 +2936,7 @@
     const auto module_str = test::ToString(p->program());
     const std::string expected = R"(var<private> x_1 : i32;
 
-var<private> position : vec4<f32>;
+var<private> position_1 : vec4<f32>;
 
 fn main_1() {
   let x_2 : i32 = x_1;
@@ -2945,14 +2945,14 @@
 
 struct main_out {
   @builtin(position)
-  position_1 : vec4<f32>,
+  position_1_1 : vec4<f32>,
 }
 
 @vertex
 fn main(@builtin(instance_index) x_1_param : u32) -> main_out {
   x_1 = bitcast<i32>(x_1_param);
   main_1();
-  return main_out(position);
+  return main_out(position_1);
 }
 )";
     EXPECT_EQ(module_str, expected) << module_str;
@@ -2995,7 +2995,7 @@
     const auto module_str = test::ToString(p->program());
     const std::string expected = R"(var<private> x_1 : u32;
 
-var<private> position : vec4<f32>;
+var<private> position_1 : vec4<f32>;
 
 fn main_1() {
   let x_2 : u32 = x_1;
@@ -3004,14 +3004,14 @@
 
 struct main_out {
   @builtin(position)
-  position_1 : vec4<f32>,
+  position_1_1 : vec4<f32>,
 }
 
 @vertex
 fn main(@builtin(instance_index) x_1_param : u32) -> main_out {
   x_1 = x_1_param;
   main_1();
-  return main_out(position);
+  return main_out(position_1);
 }
 )";
     EXPECT_EQ(module_str, expected);
@@ -3032,7 +3032,7 @@
     const auto module_str = test::ToString(p->program());
     const std::string expected = R"(var<private> x_1 : u32;
 
-var<private> position : vec4<f32>;
+var<private> position_1 : vec4<f32>;
 
 fn main_1() {
   let x_14 : ptr<private, u32> = &(x_1);
@@ -3042,14 +3042,14 @@
 
 struct main_out {
   @builtin(position)
-  position_1 : vec4<f32>,
+  position_1_1 : vec4<f32>,
 }
 
 @vertex
 fn main(@builtin(instance_index) x_1_param : u32) -> main_out {
   x_1 = x_1_param;
   main_1();
-  return main_out(position);
+  return main_out(position_1);
 }
 )";
     EXPECT_EQ(module_str, expected);
@@ -3070,7 +3070,7 @@
     const auto module_str = test::ToString(p->program());
     const std::string expected = R"(var<private> x_1 : u32;
 
-var<private> position : vec4<f32>;
+var<private> position_1 : vec4<f32>;
 
 fn main_1() {
   let x_2 : u32 = x_1;
@@ -3079,14 +3079,14 @@
 
 struct main_out {
   @builtin(position)
-  position_1 : vec4<f32>,
+  position_1_1 : vec4<f32>,
 }
 
 @vertex
 fn main(@builtin(instance_index) x_1_param : u32) -> main_out {
   x_1 = x_1_param;
   main_1();
-  return main_out(position);
+  return main_out(position_1);
 }
 )";
     EXPECT_EQ(module_str, expected);
diff --git a/src/tint/reader/spirv/parser_type.cc b/src/tint/reader/spirv/parser_type.cc
index 9051b78..0d4c58a 100644
--- a/src/tint/reader/spirv/parser_type.cc
+++ b/src/tint/reader/spirv/parser_type.cc
@@ -175,7 +175,7 @@
 
 Texture::~Texture() = default;
 
-Pointer::Pointer(const Type* t, type::AddressSpace s, type::Access a)
+Pointer::Pointer(const Type* t, builtin::AddressSpace s, builtin::Access a)
     : type(t), address_space(s), access(a) {}
 Pointer::Pointer(const Pointer&) = default;
 
@@ -189,7 +189,7 @@
     return b.ty.pointer(type->Build(b), address_space, access);
 }
 
-Reference::Reference(const Type* t, type::AddressSpace s, type::Access a)
+Reference::Reference(const Type* t, builtin::AddressSpace s, builtin::Access a)
     : type(t), address_space(s), access(a) {}
 Reference::Reference(const Reference&) = default;
 
@@ -269,7 +269,7 @@
     return b.ty.sampled_texture(dims, type->Build(b));
 }
 
-StorageTexture::StorageTexture(type::TextureDimension d, type::TexelFormat f, type::Access a)
+StorageTexture::StorageTexture(type::TextureDimension d, builtin::TexelFormat f, builtin::Access a)
     : Base(d), format(f), access(a) {}
 StorageTexture::StorageTexture(const StorageTexture&) = default;
 
@@ -474,14 +474,14 @@
 }
 
 const spirv::Pointer* TypeManager::Pointer(const Type* el,
-                                           type::AddressSpace address_space,
-                                           type::Access access) {
+                                           builtin::AddressSpace address_space,
+                                           builtin::Access access) {
     return state->pointers_.Get(el, address_space, access);
 }
 
 const spirv::Reference* TypeManager::Reference(const Type* el,
-                                               type::AddressSpace address_space,
-                                               type::Access access) {
+                                               builtin::AddressSpace address_space,
+                                               builtin::Access access) {
     return state->references_.Get(el, address_space, access);
 }
 
@@ -529,8 +529,8 @@
 }
 
 const spirv::StorageTexture* TypeManager::StorageTexture(type::TextureDimension dims,
-                                                         type::TexelFormat fmt,
-                                                         type::Access access) {
+                                                         builtin::TexelFormat fmt,
+                                                         builtin::Access access) {
     return state->storage_textures_.Get(dims, fmt, access);
 }
 
diff --git a/src/tint/reader/spirv/parser_type.h b/src/tint/reader/spirv/parser_type.h
index 9805607..8623be5 100644
--- a/src/tint/reader/spirv/parser_type.h
+++ b/src/tint/reader/spirv/parser_type.h
@@ -20,12 +20,12 @@
 #include <vector>
 
 #include "src/tint/ast/type.h"
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/address_space.h"
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/castable.h"
 #include "src/tint/symbol.h"
-#include "src/tint/type/access.h"
-#include "src/tint/type/address_space.h"
 #include "src/tint/type/sampler_kind.h"
-#include "src/tint/type/texel_format.h"
 #include "src/tint/type/texture_dimension.h"
 #include "src/tint/utils/block_allocator.h"
 
@@ -162,7 +162,7 @@
     /// @param ty the store type
     /// @param sc the pointer address space
     /// @param access the declared access mode
-    Pointer(const Type* ty, type::AddressSpace sc, type::Access access);
+    Pointer(const Type* ty, builtin::AddressSpace sc, builtin::Access access);
 
     /// Copy constructor
     /// @param other the other type to copy
@@ -180,9 +180,9 @@
     /// the store type
     Type const* const type;
     /// the pointer address space
-    type::AddressSpace const address_space;
+    builtin::AddressSpace const address_space;
     /// the pointer declared access mode
-    type::Access const access;
+    builtin::Access const access;
 };
 
 /// `ref<SC, T, AM>` type
@@ -193,7 +193,7 @@
     /// @param ty the referenced type
     /// @param sc the reference address space
     /// @param access the reference declared access mode
-    Reference(const Type* ty, type::AddressSpace sc, type::Access access);
+    Reference(const Type* ty, builtin::AddressSpace sc, builtin::Access access);
 
     /// Copy constructor
     /// @param other the other type to copy
@@ -211,9 +211,9 @@
     /// the store type
     Type const* const type;
     /// the pointer address space
-    type::AddressSpace const address_space;
+    builtin::AddressSpace const address_space;
     /// the pointer declared access mode
-    type::Access const access;
+    builtin::Access const access;
 };
 
 /// `vecN<T>` type
@@ -434,7 +434,7 @@
     /// @param d the texture dimensions
     /// @param f the storage image format
     /// @param a the access control
-    StorageTexture(type::TextureDimension d, type::TexelFormat f, type::Access a);
+    StorageTexture(type::TextureDimension d, builtin::TexelFormat f, builtin::Access a);
 
     /// Copy constructor
     /// @param other the other type to copy
@@ -450,10 +450,10 @@
 #endif  // NDEBUG
 
     /// the storage image format
-    type::TexelFormat const format;
+    builtin::TexelFormat const format;
 
     /// the access control
-    type::Access const access;
+    builtin::Access const access;
 };
 
 /// Base class for named types
@@ -549,16 +549,16 @@
     /// @return a Pointer type. Repeated calls with the same arguments will return
     /// the same pointer.
     const spirv::Pointer* Pointer(const Type* ty,
-                                  type::AddressSpace address_space,
-                                  type::Access access = type::Access::kUndefined);
+                                  builtin::AddressSpace address_space,
+                                  builtin::Access access = builtin::Access::kUndefined);
     /// @param ty the referenced type
     /// @param address_space the reference address space
     /// @param access the declared access mode
     /// @return a Reference type. Repeated calls with the same arguments will
     /// return the same pointer.
     const spirv::Reference* Reference(const Type* ty,
-                                      type::AddressSpace address_space,
-                                      type::Access access = type::Access::kUndefined);
+                                      builtin::AddressSpace address_space,
+                                      builtin::Access access = builtin::Access::kUndefined);
     /// @param ty the element type
     /// @param sz the number of elements in the vector
     /// @return a Vector type. Repeated calls with the same arguments will return
@@ -615,8 +615,8 @@
     /// @return a StorageTexture type. Repeated calls with the same arguments will
     /// return the same pointer.
     const spirv::StorageTexture* StorageTexture(type::TextureDimension d,
-                                                type::TexelFormat f,
-                                                type::Access a);
+                                                builtin::TexelFormat f,
+                                                builtin::Access a);
 
   private:
     struct State;
diff --git a/src/tint/reader/spirv/parser_type_test.cc b/src/tint/reader/spirv/parser_type_test.cc
index 232c2c5..2dd3cca 100644
--- a/src/tint/reader/spirv/parser_type_test.cc
+++ b/src/tint/reader/spirv/parser_type_test.cc
@@ -29,8 +29,8 @@
     EXPECT_EQ(ty.U32(), ty.U32());
     EXPECT_EQ(ty.F32(), ty.F32());
     EXPECT_EQ(ty.I32(), ty.I32());
-    EXPECT_EQ(ty.Pointer(ty.I32(), type::AddressSpace::kNone),
-              ty.Pointer(ty.I32(), type::AddressSpace::kNone));
+    EXPECT_EQ(ty.Pointer(ty.I32(), builtin::AddressSpace::kUndefined),
+              ty.Pointer(ty.I32(), builtin::AddressSpace::kUndefined));
     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));
@@ -43,10 +43,10 @@
               ty.MultisampledTexture(type::TextureDimension::k2d, ty.I32()));
     EXPECT_EQ(ty.SampledTexture(type::TextureDimension::k2d, ty.I32()),
               ty.SampledTexture(type::TextureDimension::k2d, ty.I32()));
-    EXPECT_EQ(ty.StorageTexture(type::TextureDimension::k2d, type::TexelFormat::kR32Uint,
-                                type::Access::kRead),
-              ty.StorageTexture(type::TextureDimension::k2d, type::TexelFormat::kR32Uint,
-                                type::Access::kRead));
+    EXPECT_EQ(ty.StorageTexture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint,
+                                builtin::Access::kRead),
+              ty.StorageTexture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint,
+                                builtin::Access::kRead));
 }
 
 TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) {
@@ -54,10 +54,10 @@
     Symbol sym_b(Symbol(2, {}));
 
     TypeManager ty;
-    EXPECT_NE(ty.Pointer(ty.I32(), type::AddressSpace::kNone),
-              ty.Pointer(ty.U32(), type::AddressSpace::kNone));
-    EXPECT_NE(ty.Pointer(ty.I32(), type::AddressSpace::kNone),
-              ty.Pointer(ty.I32(), type::AddressSpace::kIn));
+    EXPECT_NE(ty.Pointer(ty.I32(), builtin::AddressSpace::kUndefined),
+              ty.Pointer(ty.U32(), builtin::AddressSpace::kUndefined));
+    EXPECT_NE(ty.Pointer(ty.I32(), builtin::AddressSpace::kUndefined),
+              ty.Pointer(ty.I32(), builtin::AddressSpace::kIn));
     EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.U32(), 3));
     EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 2));
     EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.U32(), 3, 2));
@@ -80,18 +80,18 @@
               ty.SampledTexture(type::TextureDimension::k3d, ty.I32()));
     EXPECT_NE(ty.SampledTexture(type::TextureDimension::k2d, ty.I32()),
               ty.SampledTexture(type::TextureDimension::k2d, ty.U32()));
-    EXPECT_NE(ty.StorageTexture(type::TextureDimension::k2d, type::TexelFormat::kR32Uint,
-                                type::Access::kRead),
-              ty.StorageTexture(type::TextureDimension::k3d, type::TexelFormat::kR32Uint,
-                                type::Access::kRead));
-    EXPECT_NE(ty.StorageTexture(type::TextureDimension::k2d, type::TexelFormat::kR32Uint,
-                                type::Access::kRead),
-              ty.StorageTexture(type::TextureDimension::k2d, type::TexelFormat::kR32Sint,
-                                type::Access::kRead));
-    EXPECT_NE(ty.StorageTexture(type::TextureDimension::k2d, type::TexelFormat::kR32Uint,
-                                type::Access::kRead),
-              ty.StorageTexture(type::TextureDimension::k2d, type::TexelFormat::kR32Uint,
-                                type::Access::kWrite));
+    EXPECT_NE(ty.StorageTexture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint,
+                                builtin::Access::kRead),
+              ty.StorageTexture(type::TextureDimension::k3d, builtin::TexelFormat::kR32Uint,
+                                builtin::Access::kRead));
+    EXPECT_NE(ty.StorageTexture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint,
+                                builtin::Access::kRead),
+              ty.StorageTexture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Sint,
+                                builtin::Access::kRead));
+    EXPECT_NE(ty.StorageTexture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint,
+                                builtin::Access::kRead),
+              ty.StorageTexture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint,
+                                builtin::Access::kWrite));
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/classify_template_args.cc b/src/tint/reader/wgsl/classify_template_args.cc
index 0ccef95..79d39d2 100644
--- a/src/tint/reader/wgsl/classify_template_args.cc
+++ b/src/tint/reader/wgsl/classify_template_args.cc
@@ -70,8 +70,8 @@
 
     for (size_t i = 0; i < count - 1; i++) {
         switch (tokens[i].type()) {
-            // <identifier> + all type / builtin keywords that will become identifiers.
             case Token::Type::kIdentifier:
+            case Token::Type::kVar:
             case Token::Type::kBitcast: {
                 auto& next = tokens[i + 1];
                 if (next.type() == Token::Type::kLessThan) {
diff --git a/src/tint/reader/wgsl/lexer.cc b/src/tint/reader/wgsl/lexer.cc
index 46c15be..5171e4c 100644
--- a/src/tint/reader/wgsl/lexer.cc
+++ b/src/tint/reader/wgsl/lexer.cc
@@ -1181,8 +1181,8 @@
     if (str == "return") {
         return {Token::Type::kReturn, source, "return"};
     }
-    if (str == "static_assert") {
-        return {Token::Type::kStaticAssert, source, "static_assert"};
+    if (str == "requires") {
+        return {Token::Type::kRequires, source, "requires"};
     }
     if (str == "struct") {
         return {Token::Type::kStruct, source, "struct"};
@@ -1193,9 +1193,6 @@
     if (str == "true") {
         return {Token::Type::kTrue, source, "true"};
     }
-    if (str == "type") {
-        return {Token::Type::kType, source, "type"};
-    }
     if (str == "var") {
         return {Token::Type::kVar, source, "var"};
     }
diff --git a/src/tint/reader/wgsl/lexer_test.cc b/src/tint/reader/wgsl/lexer_test.cc
index d2a875a..95b43a7 100644
--- a/src/tint/reader/wgsl/lexer_test.cc
+++ b/src/tint/reader/wgsl/lexer_test.cc
@@ -1078,11 +1078,10 @@
                                          TokenData{"loop", Token::Type::kLoop},
                                          TokenData{"override", Token::Type::kOverride},
                                          TokenData{"return", Token::Type::kReturn},
-                                         TokenData{"static_assert", Token::Type::kStaticAssert},
+                                         TokenData{"requires", Token::Type::kRequires},
                                          TokenData{"struct", Token::Type::kStruct},
                                          TokenData{"switch", Token::Type::kSwitch},
                                          TokenData{"true", Token::Type::kTrue},
-                                         TokenData{"type", Token::Type::kType},
                                          TokenData{"var", Token::Type::kVar},
                                          TokenData{"while", Token::Type::kWhile}));
 
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index c503353..53d29f1 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -34,6 +34,7 @@
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/ast/workgroup_attribute.h"
+#include "src/tint/builtin/attribute.h"
 #include "src/tint/reader/wgsl/classify_template_args.h"
 #include "src/tint/reader/wgsl/lexer.h"
 #include "src/tint/type/depth_texture.h"
@@ -85,24 +86,25 @@
            t == "finally" || t == "friend" || t == "from" || t == "fxgroup" || t == "get" ||
            t == "goto" || t == "groupshared" || t == "handle" || t == "highp" || t == "impl" ||
            t == "implements" || t == "import" || t == "inline" || t == "inout" ||
-           t == "instanceof" || t == "interface" || t == "invariant" || t == "layout" ||
-           t == "lowp" || t == "macro" || t == "macro_rules" || t == "match" || t == "mediump" ||
-           t == "meta" || t == "mod" || t == "module" || t == "move" || t == "mut" ||
-           t == "mutable" || t == "namespace" || t == "new" || t == "nil" || t == "noexcept" ||
-           t == "noinline" || t == "nointerpolation" || t == "noperspective" || t == "null" ||
-           t == "nullptr" || t == "of" || t == "operator" || t == "package" || t == "packoffset" ||
+           t == "instanceof" || t == "interface" || t == "layout" || t == "lowp" || t == "macro" ||
+           t == "macro_rules" || t == "match" || t == "mediump" || t == "meta" || t == "mod" ||
+           t == "module" || t == "move" || t == "mut" || t == "mutable" || t == "namespace" ||
+           t == "new" || t == "nil" || t == "noexcept" || t == "noinline" ||
+           t == "nointerpolation" || t == "noperspective" || t == "null" || t == "nullptr" ||
+           t == "of" || t == "operator" || t == "package" || t == "packoffset" ||
            t == "partition" || t == "pass" || t == "patch" || t == "pixelfragment" ||
            t == "precise" || t == "precision" || t == "premerge" || t == "priv" ||
            t == "protected" || t == "pub" || t == "public" || t == "readonly" || t == "ref" ||
-           t == "regardless" || t == "register" || t == "reinterpret_cast" || t == "requires" ||
-           t == "resource" || t == "restrict" || t == "self" || t == "set" || t == "shared" ||
-           t == "signed" || t == "sizeof" || t == "smooth" || t == "snorm" || t == "static" ||
-           t == "static_cast" || t == "std" || t == "subroutine" || t == "super" || t == "target" ||
-           t == "template" || t == "this" || t == "thread_local" || t == "throw" || t == "trait" ||
-           t == "try" || t == "typedef" || t == "typeid" || t == "typename" || t == "typeof" ||
-           t == "union" || t == "unless" || t == "unorm" || t == "unsafe" || t == "unsized" ||
-           t == "use" || t == "using" || t == "varying" || t == "virtual" || t == "volatile" ||
-           t == "wgsl" || t == "where" || t == "with" || t == "writeonly" || t == "yield";
+           t == "regardless" || t == "register" || t == "reinterpret_cast" || t == "resource" ||
+           t == "restrict" || t == "self" || t == "set" || t == "shared" || t == "signed" ||
+           t == "sizeof" || t == "smooth" || t == "snorm" || t == "static" ||
+           t == "static_assert" || t == "static_cast" || t == "std" || t == "subroutine" ||
+           t == "super" || t == "target" || t == "template" || t == "this" || t == "thread_local" ||
+           t == "throw" || t == "trait" || t == "try" || t == "type" || t == "typedef" ||
+           t == "typeid" || t == "typename" || t == "typeof" || t == "union" || t == "unless" ||
+           t == "unorm" || t == "unsafe" || t == "unsized" || t == "use" || t == "using" ||
+           t == "varying" || t == "virtual" || t == "volatile" || t == "wgsl" || t == "where" ||
+           t == "with" || t == "writeonly" || t == "yield";
 }
 
 /// Enter-exit counters for block token types.
@@ -204,23 +206,6 @@
 ParserImpl::FunctionHeader& ParserImpl::FunctionHeader::operator=(const FunctionHeader& rhs) =
     default;
 
-ParserImpl::VarDeclInfo::VarDeclInfo() = default;
-
-ParserImpl::VarDeclInfo::VarDeclInfo(const VarDeclInfo&) = default;
-
-ParserImpl::VarDeclInfo::VarDeclInfo(Source source_in,
-                                     std::string name_in,
-                                     type::AddressSpace address_space_in,
-                                     type::Access access_in,
-                                     ast::Type type_in)
-    : source(std::move(source_in)),
-      name(std::move(name_in)),
-      address_space(address_space_in),
-      access(access_in),
-      type(type_in) {}
-
-ParserImpl::VarDeclInfo::~VarDeclInfo() = default;
-
 ParserImpl::ParserImpl(Source::File const* file) : file_(file) {}
 
 ParserImpl::~ParserImpl() = default;
@@ -357,6 +342,7 @@
 
 // global_directive
 //  : diagnostic_directive
+//  | requires_directive
 //  | enable_directive
 Maybe<Void> ParserImpl::global_directive(bool have_parsed_decl) {
     auto& p = peek();
@@ -364,6 +350,9 @@
     if (!result.errored && !result.matched) {
         result = enable_directive();
     }
+    if (!result.errored && !result.matched) {
+        result = requires_directive();
+    }
 
     if (result.matched && have_parsed_decl) {
         return add_error(p, "directives must come before all global declarations");
@@ -444,6 +433,67 @@
     return Failure::kNoMatch;
 }
 
+// requires_directive
+//  : require identifier (COMMA identifier)? SEMICLON
+Maybe<Void> ParserImpl::requires_directive() {
+    auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<Void> {
+        if (!match(Token::Type::kRequires)) {
+            return Failure::kNoMatch;
+        }
+
+        // Match the require name.
+        auto& t = peek();
+        if (handle_error(t)) {
+            // The token might itself be an error.
+            return Failure::kErrored;
+        }
+
+        if (t.Is(Token::Type::kParenLeft)) {
+            // A common error case is writing `require(foo);` instead of `require foo;`.
+            synchronized_ = false;
+            return add_error(t.source(), "requires directives don't take parenthesis");
+        }
+
+        while (continue_parsing()) {
+            auto& t2 = peek();
+
+            // Match the require name.
+            if (handle_error(t2)) {
+                // The token might itself be an error.
+                return Failure::kErrored;
+            }
+
+            if (t2.IsIdentifier()) {
+                // TODO(dsinclair): When there are actual values for a requires directive they
+                // should be checked here.
+
+                // Any identifer is a valid feature name, so we correctly handle new feature
+                // names getting added in the future, they just all get flagged as not supported.
+                return add_error(t2.source(), "feature '" + t2.to_str() + "' is not supported");
+            }
+            if (t2.Is(Token::Type::kSemicolon)) {
+                break;
+            }
+            if (!match(Token::Type::kComma)) {
+                return add_error(t2.source(), "invalid feature name for requires");
+            }
+        }
+        // TODO(dsinclair): When there are actual values for a requires directive then the
+        // `while` will need to keep track if any were seen, and this needs to become
+        // conditional.
+        return add_error(t.source(), "missing feature names in requires directive");
+    });
+
+    if (decl.errored) {
+        return Failure::kErrored;
+    }
+    if (decl.matched) {
+        return kSuccess;
+    }
+
+    return Failure::kNoMatch;
+}
+
 // global_decl
 //  : SEMICOLON
 //  | global_variable_decl SEMICOLON
@@ -614,13 +664,13 @@
 
     TINT_DEFER(attrs.Clear());
 
-    return builder_.Var(decl->source,         // source
-                        decl->name,           // symbol
-                        decl->type,           // type
-                        decl->address_space,  // address space
-                        decl->access,         // access control
-                        initializer,          // initializer
-                        std::move(attrs));    // attributes
+    return builder_.create<ast::Var>(decl->source,                // source
+                                     builder_.Ident(decl->name),  // symbol
+                                     decl->type,                  // type
+                                     decl->address_space,         // address space
+                                     decl->access,                // access control
+                                     initializer,                 // initializer
+                                     std::move(attrs));           // attributes
 }
 
 // global_constant_decl :
@@ -756,37 +806,28 @@
     return expect_ident_with_optional_type_specifier(use, /* allow_inferred */ false);
 }
 
-// access_mode
-//   : 'read'
-//   | 'write'
-//   | 'read_write'
-Expect<type::Access> ParserImpl::expect_access_mode(std::string_view use) {
-    return expect_enum("access control", type::ParseAccess, type::kAccessStrings, use);
-}
-
 // variable_qualifier
-//   : LESS_THAN address_spaces (COMMA access_mode)? GREATER_THAN
+//   : _template_args_start expression (COMMA expression)? _template_args_end
 Maybe<ParserImpl::VariableQualifier> ParserImpl::variable_qualifier() {
-    if (!peek_is(Token::Type::kLessThan)) {
+    if (!peek_is(Token::Type::kTemplateArgsLeft) && !peek_is(Token::Type::kLessThan)) {
+        // Note: kLessThan will give a sensible error at expect_template_arg_block()
         return Failure::kNoMatch;
     }
 
     auto* use = "variable declaration";
-    auto vq = expect_lt_gt_block(use, [&]() -> Expect<VariableQualifier> {
-        auto source = make_source_range();
-        auto sc = expect_address_space(use);
-        if (sc.errored) {
+    auto vq = expect_template_arg_block(use, [&]() -> Expect<VariableQualifier> {
+        auto address_space = expect_expression("'var' address space");
+        if (address_space.errored) {
             return Failure::kErrored;
         }
         if (match(Token::Type::kComma)) {
-            auto ac = expect_access_mode(use);
-            if (ac.errored) {
+            auto access = expect_expression("'var' access mode");
+            if (access.errored) {
                 return Failure::kErrored;
             }
-            return VariableQualifier{sc.value, ac.value};
+            return VariableQualifier{address_space.value, access.value};
         }
-        return Expect<VariableQualifier>{VariableQualifier{sc.value, type::Access::kUndefined},
-                                         source};
+        return VariableQualifier{address_space.value};
     });
 
     if (vq.errored) {
@@ -800,12 +841,7 @@
 //   : ALIAS IDENT EQUAL type_specifier
 Maybe<const ast::Alias*> ParserImpl::type_alias_decl() {
     Source source;
-    if (match(Token::Type::kAlias, &source)) {
-        // matched.
-    } else if (match(Token::Type::kType, &source)) {
-        // TODO(crbug.com/tint/1812): DEPRECATED
-        deprecated(source, "'type' has been renamed to 'alias'");
-    } else {
+    if (!match(Token::Type::kAlias, &source)) {
         return Failure::kNoMatch;
     }
 
@@ -900,18 +936,6 @@
     return type.value;
 }
 
-// address_space
-//   : 'function'
-//   | 'private'
-//   | 'workgroup'
-//   | 'uniform'
-//   | 'storage'
-//
-// Note, we also parse `push_constant` from the experimental extension
-Expect<type::AddressSpace> ParserImpl::expect_address_space(std::string_view use) {
-    return expect_enum("address space", type::ParseAddressSpace, type::kAddressSpaceStrings, use);
-}
-
 // struct_decl
 //   : STRUCT IDENT struct_body_decl
 Maybe<const ast::Struct*> ParserImpl::struct_decl() {
@@ -988,11 +1012,7 @@
 //   : STATIC_ASSERT expression
 Maybe<const ast::ConstAssert*> ParserImpl::const_assert_statement() {
     Source start;
-    if (match(Token::Type::kConstAssert, &start)) {
-        // matched
-    } else if (match(Token::Type::kStaticAssert, &start)) {
-        deprecated(start, "'static_assert' has been renamed to 'const_assert'");
-    } else {
+    if (!match(Token::Type::kConstAssert, &start)) {
         return Failure::kNoMatch;
     }
 
@@ -1149,41 +1169,6 @@
                           std::move(attrs.value));  // attributes
 }
 
-// interpolation_sample_name
-//   : 'center'
-//   | 'centroid'
-//   | 'sample'
-Expect<ast::InterpolationSampling> ParserImpl::expect_interpolation_sample_name() {
-    return expect_enum("interpolation sampling", ast::ParseInterpolationSampling,
-                       ast::kInterpolationSamplingStrings);
-}
-
-// interpolation_type_name
-//   : 'perspective'
-//   | 'linear'
-//   | 'flat'
-Expect<ast::InterpolationType> ParserImpl::expect_interpolation_type_name() {
-    return expect_enum("interpolation type", ast::ParseInterpolationType,
-                       ast::kInterpolationTypeStrings);
-}
-
-// builtin_value_name
-//   : frag_depth
-//   | front_facing
-//   | global_invocation_id
-//   | instance_index
-//   | local_invocation_id
-//   | local_invocation_index
-//   | num_workgroups
-//   | position
-//   | sample_index
-//   | sample_mask
-//   | vertex_index
-//   | workgroup_id
-Expect<builtin::BuiltinValue> ParserImpl::expect_builtin() {
-    return expect_enum("builtin", builtin::ParseBuiltinValue, builtin::kBuiltinValueStrings);
-}
-
 // compound_statement
 //   : attribute* BRACE_LEFT statement* BRACE_RIGHT
 Expect<ast::BlockStatement*> ParserImpl::expect_compound_statement(std::string_view use) {
@@ -1519,12 +1504,13 @@
         initializer = initializer_expr.value;
     }
 
-    auto* var = builder_.Var(decl_source,          // source
-                             decl->name,           // symbol
-                             decl->type,           // type
-                             decl->address_space,  // address space
-                             decl->access,         // access control
-                             initializer);         // initializer
+    auto* var = builder_.create<ast::Var>(decl_source,                 // source
+                                          builder_.Ident(decl->name),  // symbol
+                                          decl->type,                  // type
+                                          decl->address_space,         // address space
+                                          decl->access,                // access control
+                                          initializer,                 // initializer
+                                          utils::Empty);               // attributes
 
     return create<ast::VariableDeclStatement>(var->source, var);
 }
@@ -2368,37 +2354,6 @@
     return expect_additive_expression_post_unary_expression(rhs.value);
 }
 
-// element_count_expression
-//   : unary_expression math_expression.post.unary_expression
-//   | unary_expression bitwise_expression.post.unary_expression
-//
-// Note, this moves the `( multiplicative_operator unary_expression )* ( additive_operator
-// unary_expression ( multiplicative_operator unary_expression )* )*` expression for the first
-// branch out into helper methods.
-Maybe<const ast::Expression*> ParserImpl::element_count_expression() {
-    auto lhs = unary_expression();
-    if (lhs.errored) {
-        return Failure::kErrored;
-    }
-    if (!lhs.matched) {
-        return Failure::kNoMatch;
-    }
-
-    auto bitwise = bitwise_expression_post_unary_expression(lhs.value);
-    if (bitwise.errored) {
-        return Failure::kErrored;
-    }
-    if (bitwise.matched) {
-        return bitwise.value;
-    }
-
-    auto math = expect_math_expression_post_unary_expression(lhs.value);
-    if (math.errored) {
-        return Failure::kErrored;
-    }
-    return math.value;
-}
-
 // shift_expression
 //   : unary_expression shift_expression.post.unary_expression
 Maybe<const ast::Expression*> ParserImpl::shift_expression() {
@@ -2520,7 +2475,7 @@
     return create<ast::BinaryExpression>(tok_op.source(), op, lhs, rhs.value);
 }
 
-Expect<const ast::Expression*> ParserImpl::expect_expression() {
+Expect<const ast::Expression*> ParserImpl::expect_expression(std::string_view use) {
     auto& t = peek();
     auto expr = expression();
     if (expr.errored) {
@@ -2529,7 +2484,7 @@
     if (expr.matched) {
         return expr.value;
     }
-    return add_error(t, "expected expression");
+    return add_error(t, "expected expression for " + std::string(use));
 }
 
 Expect<utils::Vector<const ast::Expression*, 3>> ParserImpl::expect_expression_list(
@@ -2537,7 +2492,7 @@
     Token::Type terminator) {
     utils::Vector<const ast::Expression*, 3> exprs;
     while (continue_parsing()) {
-        auto expr = expect_expression();
+        auto expr = expect_expression(use);
         if (expr.errored) {
             return Failure::kErrored;
         }
@@ -2999,85 +2954,16 @@
 }
 
 // attribute
-//   : ATTR 'align' PAREN_LEFT expression COMMA? PAREN_RIGHT
-//   | ATTR 'binding' PAREN_LEFT expression COMMA? PAREN_RIGHT
-//   | ATTR 'builtin' PAREN_LEFT builtin_value_name COMMA? PAREN_RIGHT
-//   | ATTR 'const'
-//   | ATTR 'diagnostic' diagnostic_control
-//   | ATTR 'group' PAREN_LEFT expression COMMA? PAREN_RIGHT
-//   | ATTR 'id' PAREN_LEFT expression COMMA? PAREN_RIGHT
-//   | ATTR 'interpolate' PAREN_LEFT interpolation_type_name COMMA? PAREN_RIGHT
-//   | ATTR 'interpolate' PAREN_LEFT interpolation_type_name COMMA
-//                                   interpolation_sample_name COMMA? PAREN_RIGHT
-//   | ATTR 'invariant'
-//   | ATTR 'location' PAREN_LEFT expression COMMA? PAREN_RIGHT
-//   | ATTR 'size' PAREN_LEFT expression COMMA? PAREN_RIGHT
-//   | ATTR 'workgroup_size' PAREN_LEFT expression COMMA? PAREN_RIGHT
-//   | ATTR 'workgroup_size' PAREN_LEFT expression COMMA expression COMMA? PAREN_RIGHT
-//   | ATTR 'workgroup_size' PAREN_LEFT expression COMMA expression COMMA
-//                                      expression COMMA? PAREN_RIGHT
-//   | ATTR 'vertex'
-//   | ATTR 'fragment'
-//   | ATTR 'compute'
+//   : ATTR identifier ( PAREN_LEFT expression ( COMMA expression )? COMMA? PAREN_RIGHT )?
 Maybe<const ast::Attribute*> ParserImpl::attribute() {
-    using Result = Maybe<const ast::Attribute*>;
-    auto& t = next();
+    // Note, the ATTR is matched by the called `attribute_list` in this case, so it is not matched
+    // here and this has to be an attribute.
+    auto& t = peek();
 
-    if (!t.IsIdentifier() && !(t.Is(Token::Type::kDiagnostic))) {
-        return Failure::kNoMatch;
+    if (match(Token::Type::kConst)) {
+        return add_error(t.source(), "const attribute may not appear in shaders");
     }
-
-    if (t == "align") {
-        const char* use = "align attribute";
-        return expect_paren_block(use, [&]() -> Result {
-            auto expr = expression();
-            if (expr.errored) {
-                return Failure::kErrored;
-            }
-            if (!expr.matched) {
-                return add_error(peek(), "expected align expression");
-            }
-            match(Token::Type::kComma);
-
-            return create<ast::StructMemberAlignAttribute>(t.source(), expr.value);
-        });
-    }
-
-    if (t == "binding") {
-        const char* use = "binding attribute";
-        return expect_paren_block(use, [&]() -> Result {
-            auto expr = expression();
-            if (expr.errored) {
-                return Failure::kErrored;
-            }
-            if (!expr.matched) {
-                return add_error(peek(), "expected binding expression");
-            }
-            match(Token::Type::kComma);
-
-            return create<ast::BindingAttribute>(t.source(), expr.value);
-        });
-    }
-
-    if (t == "builtin") {
-        return expect_paren_block("builtin attribute", [&]() -> Result {
-            auto builtin = expect_builtin();
-            if (builtin.errored) {
-                return Failure::kErrored;
-            }
-            match(Token::Type::kComma);
-
-            return create<ast::BuiltinAttribute>(t.source(), builtin.value);
-        });
-    }
-
-    if (t == "compute") {
-        return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kCompute);
-    }
-
-    // Note, `const` is not valid in a WGSL source file, it's internal only
-
-    if (t.Is(Token::Type::kDiagnostic)) {
+    if (match(Token::Type::kDiagnostic)) {
         auto control = expect_diagnostic_control();
         if (control.errored) {
             return Failure::kErrored;
@@ -3085,150 +2971,111 @@
         return create<ast::DiagnosticAttribute>(t.source(), std::move(control.value));
     }
 
-    if (t == "fragment") {
-        return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kFragment);
+    auto attr = expect_enum("attribute", builtin::ParseAttribute, builtin::kAttributeStrings);
+    if (attr.errored) {
+        return Failure::kErrored;
     }
 
-    if (t == "group") {
-        const char* use = "group attribute";
-        return expect_paren_block(use, [&]() -> Result {
-            auto expr = expression();
-            if (expr.errored) {
-                return Failure::kErrored;
-            }
-            if (!expr.matched) {
-                return add_error(peek(), "expected group expression");
-            }
-            match(Token::Type::kComma);
-
-            return create<ast::GroupAttribute>(t.source(), expr.value);
-        });
+    uint32_t min = 1;
+    uint32_t max = 1;
+    switch (attr.value) {
+        case builtin::Attribute::kCompute:
+        case builtin::Attribute::kFragment:
+        case builtin::Attribute::kInvariant:
+        case builtin::Attribute::kMustUse:
+        case builtin::Attribute::kVertex:
+            min = 0;
+            max = 0;
+            break;
+        case builtin::Attribute::kInterpolate:
+            max = 2;
+            break;
+        case builtin::Attribute::kWorkgroupSize:
+            max = 3;
+            break;
+        default:
+            break;
     }
 
-    if (t == "id") {
-        const char* use = "id attribute";
-        return expect_paren_block(use, [&]() -> Result {
-            auto expr = expression();
-            if (expr.errored) {
-                return Failure::kErrored;
-            }
-            if (!expr.matched) {
-                return add_error(peek(), "expected id expression");
-            }
-            match(Token::Type::kComma);
+    utils::Vector<const ast::Expression*, 2> args;
 
-            return create<ast::IdAttribute>(t.source(), expr.value);
-        });
-    }
+    // Handle no parameter items which should have no parens
+    if (min == 0) {
+        auto& t2 = peek();
+        if (match(Token::Type::kParenLeft)) {
+            return add_error(t2.source(), t.to_str() + " attribute doesn't take parenthesis");
+        }
+    } else {
+        auto res = expect_paren_block(t.to_str() + " attribute", [&]() -> Expect<bool> {
+            while (continue_parsing()) {
+                if (peek().Is(Token::Type::kParenRight)) {
+                    break;
+                }
 
-    if (t == "interpolate") {
-        return expect_paren_block("interpolate attribute", [&]() -> Result {
-            auto type = expect_interpolation_type_name();
-            if (type.errored) {
-                return Failure::kErrored;
-            }
+                auto expr = expect_expression(t.to_str());
+                if (expr.errored) {
+                    return Failure::kErrored;
+                }
+                args.Push(expr.value);
 
-            ast::InterpolationSampling sampling = ast::InterpolationSampling::kUndefined;
-            if (match(Token::Type::kComma)) {
-                if (!peek_is(Token::Type::kParenRight)) {
-                    auto sample = expect_interpolation_sample_name();
-                    if (sample.errored) {
-                        return Failure::kErrored;
-                    }
-
-                    sampling = sample.value;
-                    match(Token::Type::kComma);
+                if (!match(Token::Type::kComma)) {
+                    break;
                 }
             }
-
-            return create<ast::InterpolateAttribute>(t.source(), type.value, sampling);
+            return true;
         });
+        if (res.errored) {
+            return Failure::kErrored;
+        }
+
+        if (args.IsEmpty() || args.Length() < min) {
+            return add_error(t.source(),
+                             t.to_str() + " expects" + (min != max ? " at least " : " ") +
+                                 std::to_string(min) + " argument" + (min != 1 ? "s" : ""));
+        }
+        if (args.Length() > max) {
+            return add_error(t.source(),
+                             t.to_str() + " expects" + (min != max ? " at most " : " ") +
+                                 std::to_string(max) + " argument" + (max != 1 ? "s" : "") +
+                                 ", got " + std::to_string(args.Length()));
+        }
     }
 
-    if (t == "invariant") {
-        return create<ast::InvariantAttribute>(t.source());
+    switch (attr.value) {
+        case builtin::Attribute::kAlign:
+            return create<ast::StructMemberAlignAttribute>(t.source(), args[0]);
+        case builtin::Attribute::kBinding:
+            return create<ast::BindingAttribute>(t.source(), args[0]);
+        case builtin::Attribute::kBuiltin:
+            return create<ast::BuiltinAttribute>(t.source(), args[0]);
+        case builtin::Attribute::kCompute:
+            return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kCompute);
+        case builtin::Attribute::kFragment:
+            return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kFragment);
+        case builtin::Attribute::kGroup:
+            return create<ast::GroupAttribute>(t.source(), args[0]);
+        case builtin::Attribute::kId:
+            return create<ast::IdAttribute>(t.source(), args[0]);
+        case builtin::Attribute::kInterpolate:
+            return create<ast::InterpolateAttribute>(t.source(), args[0],
+                                                     args.Length() == 2 ? args[1] : nullptr);
+        case builtin::Attribute::kInvariant:
+            return create<ast::InvariantAttribute>(t.source());
+        case builtin::Attribute::kLocation:
+            return builder_.Location(t.source(), args[0]);
+        case builtin::Attribute::kMustUse:
+            return create<ast::MustUseAttribute>(t.source());
+        case builtin::Attribute::kSize:
+            return builder_.MemberSize(t.source(), args[0]);
+        case builtin::Attribute::kVertex:
+            return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kVertex);
+        case builtin::Attribute::kWorkgroupSize:
+            return create<ast::WorkgroupAttribute>(t.source(), args[0],
+                                                   args.Length() > 1 ? args[1] : nullptr,
+                                                   args.Length() > 2 ? args[2] : nullptr);
+        default:
+            return Failure::kNoMatch;
     }
-
-    if (t == "location") {
-        const char* use = "location attribute";
-        return expect_paren_block(use, [&]() -> Result {
-            auto expr = expression();
-            if (expr.errored) {
-                return Failure::kErrored;
-            }
-            if (!expr.matched) {
-                return add_error(peek(), "expected location expression");
-            }
-            match(Token::Type::kComma);
-
-            return builder_.Location(t.source(), expr.value);
-        });
-    }
-
-    if (t == "size") {
-        const char* use = "size attribute";
-        return expect_paren_block(use, [&]() -> Result {
-            auto expr = expression();
-            if (expr.errored) {
-                return Failure::kErrored;
-            }
-            if (!expr.matched) {
-                return add_error(peek(), "expected size expression");
-            }
-            match(Token::Type::kComma);
-
-            return builder_.MemberSize(t.source(), expr.value);
-        });
-    }
-
-    if (t == "vertex") {
-        return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kVertex);
-    }
-
-    if (t == "workgroup_size") {
-        return expect_paren_block("workgroup_size attribute", [&]() -> Result {
-            const ast::Expression* x = nullptr;
-            const ast::Expression* y = nullptr;
-            const ast::Expression* z = nullptr;
-
-            auto expr = expression();
-            if (expr.errored) {
-                return Failure::kErrored;
-            } else if (!expr.matched) {
-                return add_error(peek(), "expected workgroup_size x parameter");
-            }
-            x = std::move(expr.value);
-
-            if (match(Token::Type::kComma)) {
-                if (!peek_is(Token::Type::kParenRight)) {
-                    expr = expression();
-                    if (expr.errored) {
-                        return Failure::kErrored;
-                    } else if (!expr.matched) {
-                        return add_error(peek(), "expected workgroup_size y parameter");
-                    }
-                    y = std::move(expr.value);
-
-                    if (match(Token::Type::kComma)) {
-                        if (!peek_is(Token::Type::kParenRight)) {
-                            expr = expression();
-                            if (expr.errored) {
-                                return Failure::kErrored;
-                            } else if (!expr.matched) {
-                                return add_error(peek(), "expected workgroup_size z parameter");
-                            }
-                            z = std::move(expr.value);
-
-                            match(Token::Type::kComma);
-                        }
-                    }
-                }
-            }
-
-            return create<ast::WorkgroupAttribute>(t.source(), x, y, z);
-        });
-    }
-    return Failure::kNoMatch;
 }
 
 bool ParserImpl::expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> in) {
@@ -3244,9 +3091,9 @@
 //   | 'warning'
 //   | 'info'
 //   | 'off'
-Expect<ast::DiagnosticSeverity> ParserImpl::expect_severity_control_name() {
-    return expect_enum("severity control", ast::ParseDiagnosticSeverity,
-                       ast::kDiagnosticSeverityStrings);
+Expect<builtin::DiagnosticSeverity> ParserImpl::expect_severity_control_name() {
+    return expect_enum("severity control", builtin::ParseDiagnosticSeverity,
+                       builtin::kDiagnosticSeverityStrings);
 }
 
 // diagnostic_control
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index fe42cac..bfc2f9a 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -22,6 +22,7 @@
 #include <utility>
 #include <vector>
 
+#include "src/tint/builtin/access.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/reader/wgsl/parser_impl_detail.h"
 #include "src/tint/reader/wgsl/token.h"
@@ -148,10 +149,9 @@
 
         /// Constructor for a successful parse.
         /// @param val the result value of the parse
-        /// @param s the optional source of the value
         template <typename U>
-        inline Maybe(U&& val, const Source& s = {})  // NOLINT
-            : value(std::forward<U>(val)), source(s), matched(true) {}
+        inline Maybe(U&& val)  // NOLINT
+            : value(std::forward<U>(val)), matched(true) {}
 
         /// Constructor for parse error state.
         inline Maybe(Failure::Errored) : errored(true) {}  // NOLINT
@@ -163,16 +163,13 @@
         /// @param e the Expect to copy this Maybe from
         template <typename U>
         inline Maybe(const Expect<U>& e)  // NOLINT
-            : value(e.value), source(e.value), errored(e.errored), matched(!e.errored) {}
+            : value(e.value), errored(e.errored), matched(!e.errored) {}
 
         /// Move from an Expect.
         /// @param e the Expect to move this Maybe from
         template <typename U>
         inline Maybe(Expect<U>&& e)  // NOLINT
-            : value(std::move(e.value)),
-              source(std::move(e.source)),
-              errored(e.errored),
-              matched(!e.errored) {}
+            : value(std::move(e.value)), errored(e.errored), matched(!e.errored) {}
 
         /// Copy constructor
         inline Maybe(const Maybe&) = default;
@@ -197,8 +194,6 @@
         /// The value of a successful parse.
         /// Zero-initialized when there was a parse error.
         T value{};
-        /// Optional source of the value.
-        Source source;
         /// True if there was a error parsing.
         bool errored = false;
         /// True if there was a error parsing.
@@ -268,33 +263,14 @@
 
     /// VarDeclInfo contains the parsed information for variable declaration.
     struct VarDeclInfo {
-        /// Constructor
-        VarDeclInfo();
-        /// Copy constructor
-        /// @param other the VarDeclInfo to copy
-        VarDeclInfo(const VarDeclInfo& other);
-        /// Constructor
-        /// @param source_in variable declaration source
-        /// @param name_in variable name
-        /// @param address_space_in variable address space
-        /// @param access_in variable access control
-        /// @param type_in variable type
-        VarDeclInfo(Source source_in,
-                    std::string name_in,
-                    type::AddressSpace address_space_in,
-                    type::Access access_in,
-                    ast::Type type_in);
-        /// Destructor
-        ~VarDeclInfo();
-
         /// Variable declaration source
         Source source;
         /// Variable name
         std::string name;
         /// Variable address space
-        type::AddressSpace address_space = type::AddressSpace::kNone;
+        const ast::Expression* address_space = nullptr;
         /// Variable access control
-        type::Access access = type::Access::kUndefined;
+        const ast::Expression* access = nullptr;
         /// Variable type
         ast::Type type;
     };
@@ -302,9 +278,9 @@
     /// VariableQualifier contains the parsed information for a variable qualifier
     struct VariableQualifier {
         /// The variable's address space
-        type::AddressSpace address_space = type::AddressSpace::kNone;
+        const ast::Expression* address_space = nullptr;
         /// The variable's access control
-        type::Access access = type::Access::kUndefined;
+        const ast::Expression* access = nullptr;
     };
 
     /// MatrixDimensions contains the column and row information for a matrix
@@ -405,6 +381,9 @@
     /// Parses the `enable_directive` grammar element, erroring on parse failure.
     /// @return true on parse success, otherwise an error or no-match.
     Maybe<Void> enable_directive();
+    /// Parses the `requires_directive` grammar element, erroring on parse failure.
+    /// @return true on parse success, otherwise an error or no-match.
+    Maybe<Void> requires_directive();
     /// Parses the `global_decl` grammar element, erroring on parse failure.
     /// @return true on parse success, otherwise an error or no-match.
     Maybe<Void> global_decl();
@@ -447,10 +426,6 @@
     /// Parses a `type_specifier` grammar element
     /// @returns the parsed Type or nullptr if none matched.
     Maybe<ast::Type> type_specifier();
-    /// Parses an `address_space` grammar element, erroring on parse failure.
-    /// @param use a description of what was being parsed if an error was raised.
-    /// @returns the address space or type::AddressSpace::kNone if none matched
-    Expect<type::AddressSpace> expect_address_space(std::string_view use);
     /// Parses a `struct_decl` grammar element.
     /// @returns the struct type or nullptr on error
     Maybe<const ast::Struct*> struct_decl();
@@ -482,23 +457,6 @@
     /// not match a stage name.
     /// @returns the pipeline stage.
     Expect<ast::PipelineStage> expect_pipeline_stage();
-    /// 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<type::Access> expect_access_mode(std::string_view use);
-    /// Parses an interpolation sample name identifier, erroring if the next token does not match a
-    /// valid sample name.
-    /// @returns the parsed sample name.
-    Expect<ast::InterpolationSampling> expect_interpolation_sample_name();
-    /// Parses an interpolation type name identifier, erroring if the next token does not match a
-    /// value type name.
-    /// @returns the parsed type name
-    Expect<ast::InterpolationType> expect_interpolation_type_name();
-    /// Parses a builtin identifier, erroring if the next token does not match a
-    /// valid builtin name.
-    /// @returns the parsed builtin.
-    Expect<builtin::BuiltinValue> expect_builtin();
     /// Parses a `compound_statement` grammar element, erroring on parse failure.
     /// @param use a description of what was being parsed if an error was raised
     /// @returns the parsed statements
@@ -597,8 +555,9 @@
     /// @returns the parsed expression or nullptr
     Maybe<const ast::Expression*> expression();
     /// Parses the `expression` grammar rule
+    /// @param use the use of the expression
     /// @returns the parsed expression or error
-    Expect<const ast::Expression*> expect_expression();
+    Expect<const ast::Expression*> expect_expression(std::string_view use);
     /// Parses a comma separated expression list
     /// @param use the use of the expression list
     /// @param terminator the terminating token for the list
@@ -628,9 +587,6 @@
     /// @returns the parsed expression or `lhs` if no match
     Expect<const ast::Expression*> expect_math_expression_post_unary_expression(
         const ast::Expression* lhs);
-    /// Parses an `element_count_expression` grammar element
-    /// @returns the parsed expression or nullptr
-    Maybe<const ast::Expression*> element_count_expression();
     /// Parses a `unary_expression shift.post.unary_expression`
     /// @returns the parsed expression or nullptr
     Maybe<const ast::Expression*> shift_expression();
@@ -681,7 +637,7 @@
     Expect<const ast::Attribute*> expect_attribute();
     /// Parses a severity_control_name grammar element.
     /// @return the parsed severity control name, or nullptr on error.
-    Expect<ast::DiagnosticSeverity> expect_severity_control_name();
+    Expect<builtin::DiagnosticSeverity> expect_severity_control_name();
     /// Parses a diagnostic_control grammar element.
     /// @return the parsed diagnostic control, or nullptr on error.
     Expect<ast::DiagnosticControl> expect_diagnostic_control();
@@ -882,7 +838,7 @@
 
     /// Creates a new `ast::Node` owned by the Module. When the Module is
     /// destructed, the `ast::Node` will also be destructed.
-    /// @param args the arguments to pass to the type constructor
+    /// @param args the arguments to pass to the constructor
     /// @returns the node pointer
     template <typename T, typename... ARGS>
     T* create(ARGS&&... args) {
diff --git a/src/tint/reader/wgsl/parser_impl_address_space_test.cc b/src/tint/reader/wgsl/parser_impl_address_space_test.cc
deleted file mode 100644
index 32c3c47..0000000
--- a/src/tint/reader/wgsl/parser_impl_address_space_test.cc
+++ /dev/null
@@ -1,62 +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/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-struct AddressSpaceData {
-    const char* input;
-    type::AddressSpace result;
-};
-inline std::ostream& operator<<(std::ostream& out, AddressSpaceData data) {
-    out << std::string(data.input);
-    return out;
-}
-
-class ParserAddressSpaceTest : public ParserImplTestWithParam<AddressSpaceData> {};
-
-TEST_P(ParserAddressSpaceTest, Parses) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-
-    auto sc = p->expect_address_space("test");
-    EXPECT_FALSE(sc.errored);
-    EXPECT_FALSE(p->has_error());
-    EXPECT_EQ(sc.value, params.result);
-
-    auto& t = p->next();
-    EXPECT_TRUE(t.IsEof());
-}
-INSTANTIATE_TEST_SUITE_P(
-    ParserImplTest,
-    ParserAddressSpaceTest,
-    testing::Values(AddressSpaceData{"uniform", type::AddressSpace::kUniform},
-                    AddressSpaceData{"workgroup", type::AddressSpace::kWorkgroup},
-                    AddressSpaceData{"storage", type::AddressSpace::kStorage},
-                    AddressSpaceData{"private", type::AddressSpace::kPrivate},
-                    AddressSpaceData{"function", type::AddressSpace::kFunction}));
-
-TEST_F(ParserImplTest, AddressSpace_NoMatch) {
-    auto p = parser("not-a-address-space");
-    auto sc = p->expect_address_space("test");
-    EXPECT_EQ(sc.errored, true);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:1: expected address space for test
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
index 6c5e6f6..5c54e93 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
@@ -27,7 +27,7 @@
     EXPECT_TRUE(a.matched);
     auto* d = a.value->As<ast::DiagnosticAttribute>();
     ASSERT_NE(d, nullptr);
-    EXPECT_EQ(d->control.severity, ast::DiagnosticSeverity::kOff);
+    EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kOff);
     auto* r = d->control.rule_name;
     ASSERT_NE(r, nullptr);
     ast::CheckIdentifier(p->builder().Symbols(), r, "foo");
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
index 4454a9d..81ce178 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
@@ -20,7 +20,7 @@
 namespace tint::reader::wgsl {
 namespace {
 
-using SeverityPair = std::pair<std::string, ast::DiagnosticSeverity>;
+using SeverityPair = std::pair<std::string, builtin::DiagnosticSeverity>;
 class DiagnosticControlParserTest : public ParserImplTestWithParam<SeverityPair> {};
 
 TEST_P(DiagnosticControlParserTest, DiagnosticControl_Valid) {
@@ -37,17 +37,18 @@
 }
 INSTANTIATE_TEST_SUITE_P(DiagnosticControlParserTest,
                          DiagnosticControlParserTest,
-                         testing::Values(SeverityPair{"error", ast::DiagnosticSeverity::kError},
-                                         SeverityPair{"warning", ast::DiagnosticSeverity::kWarning},
-                                         SeverityPair{"info", ast::DiagnosticSeverity::kInfo},
-                                         SeverityPair{"off", ast::DiagnosticSeverity::kOff}));
+                         testing::Values(SeverityPair{"error", builtin::DiagnosticSeverity::kError},
+                                         SeverityPair{"warning",
+                                                      builtin::DiagnosticSeverity::kWarning},
+                                         SeverityPair{"info", builtin::DiagnosticSeverity::kInfo},
+                                         SeverityPair{"off", builtin::DiagnosticSeverity::kOff}));
 
 TEST_F(ParserImplTest, DiagnosticControl_Valid_TrailingComma) {
     auto p = parser("(error, foo,)");
     auto e = p->expect_diagnostic_control();
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
-    EXPECT_EQ(e->severity, ast::DiagnosticSeverity::kError);
+    EXPECT_EQ(e->severity, builtin::DiagnosticSeverity::kError);
 
     auto* r = e->rule_name;
     ASSERT_NE(r, nullptr);
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
index ab50f34..b2f987c 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
@@ -27,7 +27,7 @@
     auto& ast = p->builder().AST();
     ASSERT_EQ(ast.DiagnosticDirectives().Length(), 1u);
     auto* directive = ast.DiagnosticDirectives()[0];
-    EXPECT_EQ(directive->control.severity, ast::DiagnosticSeverity::kOff);
+    EXPECT_EQ(directive->control.severity, builtin::DiagnosticSeverity::kOff);
     ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
     EXPECT_EQ(ast.GlobalDeclarations()[0], directive);
 
diff --git a/src/tint/reader/wgsl/parser_impl_element_count_expression_test.cc b/src/tint/reader/wgsl/parser_impl_element_count_expression_test.cc
deleted file mode 100644
index b629ef7..0000000
--- a/src/tint/reader/wgsl/parser_impl_element_count_expression_test.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2022 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/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, ElementCountExpression_Math) {
-    auto p = parser("a * b");
-    auto e = p->element_count_expression();
-    EXPECT_TRUE(e.matched);
-    EXPECT_FALSE(e.errored);
-    EXPECT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(e.value, nullptr);
-
-    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-    auto* rel = e->As<ast::BinaryExpression>();
-    EXPECT_EQ(ast::BinaryOp::kMultiply, rel->op);
-
-    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-    auto* ident_expr = rel->lhs->As<ast::IdentifierExpression>();
-    EXPECT_EQ(ident_expr->identifier->symbol, p->builder().Symbols().Get("a"));
-
-    ASSERT_TRUE(rel->rhs->Is<ast::IdentifierExpression>());
-    ident_expr = rel->rhs->As<ast::IdentifierExpression>();
-    EXPECT_EQ(ident_expr->identifier->symbol, p->builder().Symbols().Get("b"));
-}
-
-TEST_F(ParserImplTest, ElementCountExpression_Bitwise) {
-    auto p = parser("a | true");
-    auto e = p->element_count_expression();
-    EXPECT_TRUE(e.matched);
-    EXPECT_FALSE(e.errored);
-    EXPECT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(e.value, nullptr);
-
-    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-    auto* rel = e->As<ast::BinaryExpression>();
-    EXPECT_EQ(ast::BinaryOp::kOr, rel->op);
-
-    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-    auto* ident_expr = rel->lhs->As<ast::IdentifierExpression>();
-    EXPECT_EQ(ident_expr->identifier->symbol, p->builder().Symbols().Get("a"));
-
-    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
-}
-
-TEST_F(ParserImplTest, ElementCountExpression_NoMatch) {
-    auto p = parser("if (a) { }");
-    auto e = p->element_count_expression();
-    EXPECT_FALSE(e.matched);
-    EXPECT_FALSE(e.errored);
-    EXPECT_FALSE(p->has_error()) << p->error();
-    ASSERT_EQ(e.value, nullptr);
-}
-
-TEST_F(ParserImplTest, ElementCountExpression_InvalidRHS) {
-    auto p = parser("a * if");
-    auto e = p->element_count_expression();
-    EXPECT_FALSE(e.matched);
-    EXPECT_TRUE(e.errored);
-    EXPECT_TRUE(p->has_error());
-    ASSERT_EQ(e.value, nullptr);
-    EXPECT_EQ("1:5: unable to parse right side of * expression", p->error());
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
index d40898a..85e55cb 100644
--- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -52,18 +52,21 @@
 }
 
 TEST_F(ParserImplErrorTest, AliasDeclInvalidAttribute) {
-    EXPECT(
-        "@invariant type e=u32;",
-        R"(test.wgsl:1:12 warning: use of deprecated language feature: 'type' has been renamed to 'alias'
-@invariant type e=u32;
-           ^^^^
-
-test.wgsl:1:2 error: unexpected attributes
-@invariant type e=u32;
+    EXPECT("@invariant alias e=u32;",
+           R"(test.wgsl:1:2 error: unexpected attributes
+@invariant alias e=u32;
  ^^^^^^^^^
 )");
 }
 
+TEST_F(ParserImplErrorTest, ConstAttributeInvalid) {
+    EXPECT("@const fn main() { }",
+           R"(test.wgsl:1:2 error: const attribute may not appear in shaders
+@const fn main() { }
+ ^^^^^
+)");
+}
+
 TEST_F(ParserImplErrorTest, IndexExprInvalidExpr) {
     EXPECT("fn f() { x = y[^]; }",
            R"(test.wgsl:1:16 error: unable to parse expression inside []
@@ -356,101 +359,17 @@
 )");
 }
 
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplErrorTest, DEPRECATED_FunctionDeclStaticAssertMissingCondThenEOF) {
-    EXPECT(
-        "fn f() { static_assert }",
-        R"(test.wgsl:1:10 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-fn f() { static_assert }
-         ^^^^^^^^^^^^^
-
-test.wgsl:1:24 error: unable to parse condition expression
-fn f() { static_assert }
-                       ^
-)");
-}
-
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplErrorTest, DEPRECATED_FunctionDeclStaticAssertMissingCondThenSemicolon) {
-    EXPECT(
-        "fn f() { static_assert; }",
-        R"(test.wgsl:1:10 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-fn f() { static_assert; }
-         ^^^^^^^^^^^^^
-
-test.wgsl:1:23 error: unable to parse condition expression
-fn f() { static_assert; }
-                      ^
-)");
-}
-
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplErrorTest, DEPRECATED_FunctionDeclStaticAssertMissingCondThenLet) {
-    EXPECT(
-        "fn f() { static_assert\nlet x = 0; }",
-        R"(test.wgsl:1:10 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-fn f() { static_assert
-         ^^^^^^^^^^^^^
-
-test.wgsl:2:1 error: unable to parse condition expression
-let x = 0; }
-^^^
-)");
-}
-
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplErrorTest, DEPRECATED_FunctionDeclStaticAssertMissingLParen) {
-    EXPECT(
-        "fn f() { static_assert true);",
-        R"(test.wgsl:1:10 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-fn f() { static_assert true);
-         ^^^^^^^^^^^^^
-
-test.wgsl:1:28 error: expected ';' for statement
-fn f() { static_assert true);
-                           ^
-)");
-}
-
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplErrorTest, DEPRECATED_FunctionDeclStaticAssertMissingRParen) {
-    EXPECT(
-        "fn f() { static_assert (true;",
-        R"(test.wgsl:1:10 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-fn f() { static_assert (true;
-         ^^^^^^^^^^^^^
-
-test.wgsl:1:29 error: expected ')'
-fn f() { static_assert (true;
-                            ^
-)");
-}
-
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplErrorTest, DEPRECATED_FunctionDeclStaticAssertMissingSemicolon) {
-    EXPECT(
-        "fn f() { static_assert true }",
-        R"(test.wgsl:1:10 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-fn f() { static_assert true }
-         ^^^^^^^^^^^^^
-
-test.wgsl:1:29 error: expected ';' for statement
-fn f() { static_assert true }
-                            ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeXInvalid) {
     EXPECT("@workgroup_size() fn f() {}",
-           R"(test.wgsl:1:17 error: expected workgroup_size x parameter
+           R"(test.wgsl:1:2 error: workgroup_size expects at least 1 argument
 @workgroup_size() fn f() {}
-                ^
+ ^^^^^^^^^^^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeYInvalid) {
     EXPECT("@workgroup_size(1, fn) fn f() {}",
-           R"(test.wgsl:1:20 error: expected workgroup_size y parameter
+           R"(test.wgsl:1:20 error: expected expression for workgroup_size
 @workgroup_size(1, fn) fn f() {}
                    ^^
 )");
@@ -458,7 +377,7 @@
 
 TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeZInvalid) {
     EXPECT("@workgroup_size(1, 2, fn) fn f() {}",
-           R"(test.wgsl:1:23 error: expected workgroup_size z parameter
+           R"(test.wgsl:1:23 error: expected expression for workgroup_size
 @workgroup_size(1, 2, fn) fn f() {}
                       ^^
 )");
@@ -681,10 +600,10 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstAssertMissingCondThenAlias) {
-    EXPECT("const_assert\ntype T = i32;",
+    EXPECT("const_assert\nalias T = i32;",
            R"(test.wgsl:2:1 error: unable to parse condition expression
-type T = i32;
-^^^^
+alias T = i32;
+^^^^^
 )");
 }
 
@@ -711,84 +630,6 @@
 )");
 }
 
-// TODO(crbug.com/tint/1807): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclStaticAssertMissingCondThenEOF) {
-    EXPECT("const_assert", R"(test.wgsl:1:13 error: unable to parse condition expression
-const_assert
-            ^
-)");
-}
-
-// TODO(crbug.com/tint/1807): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclStaticAssertMissingCondThenSemicolon) {
-    EXPECT(
-        "static_assert;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-static_assert;
-^^^^^^^^^^^^^
-
-test.wgsl:1:14 error: unable to parse condition expression
-static_assert;
-             ^
-)");
-}
-
-// TODO(crbug.com/tint/1807): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclStaticAssertMissingCondThenAlias) {
-    EXPECT(
-        "static_assert\ntype T = i32;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-static_assert
-^^^^^^^^^^^^^
-
-test.wgsl:2:1 error: unable to parse condition expression
-type T = i32;
-^^^^
-)");
-}
-
-// TODO(crbug.com/tint/1807): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclStaticAssertMissingLParen) {
-    EXPECT(
-        "static_assert true);",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-static_assert true);
-^^^^^^^^^^^^^
-
-test.wgsl:1:19 error: expected ';' for const assertion declaration
-static_assert true);
-                  ^
-)");
-}
-
-// TODO(crbug.com/tint/1807): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclStaticAssertMissingRParen) {
-    EXPECT(
-        "static_assert (true;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-static_assert (true;
-^^^^^^^^^^^^^
-
-test.wgsl:1:20 error: expected ')'
-static_assert (true;
-                   ^
-)");
-}
-
-// TODO(crbug.com/tint/1807): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclStaticAssertMissingSemicolon) {
-    EXPECT(
-        "static_assert true static_assert true;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: 'static_assert' has been renamed to 'const_assert'
-static_assert true static_assert true;
-^^^^^^^^^^^^^
-
-test.wgsl:1:20 error: expected ';' for const assertion declaration
-static_assert true static_assert true;
-                   ^^^^^^^^^^^^^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingGreaterThan) {
     EXPECT("var x : texture_storage_2d<r32uint, read;",
            R"(test.wgsl:1:27 error: expected ';' for variable declaration
@@ -799,7 +640,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingSubtype) {
     EXPECT("var x : texture_storage_2d<>;",
-           R"(test.wgsl:1:28 error: expected expression
+           R"(test.wgsl:1:28 error: expected expression for type template argument list
 var x : texture_storage_2d<>;
                            ^
 )");
@@ -839,7 +680,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberAlignInvaldValue) {
     EXPECT("struct S { @align(fn) i : i32, };",
-           R"(test.wgsl:1:19 error: expected align expression
+           R"(test.wgsl:1:19 error: expected expression for align
 struct S { @align(fn) i : i32, };
                   ^^
 )");
@@ -847,7 +688,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberSizeInvaldValue) {
     EXPECT("struct S { @size(if) i : i32, };",
-           R"(test.wgsl:1:18 error: expected size expression
+           R"(test.wgsl:1:18 error: expected expression for size
 struct S { @size(if) i : i32, };
                  ^^
 )");
@@ -882,57 +723,6 @@
 )");
 }
 
-// TODO(crbug.com/tint/1812): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclTypeAliasMissingIdentifier) {
-    EXPECT("alias 1 = f32;",
-           R"(test.wgsl:1:7 error: expected identifier for type alias
-alias 1 = f32;
-      ^
-)");
-}
-
-// TODO(crbug.com/tint/1812): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclTypeAliasInvalidType) {
-    EXPECT(
-        "type meow = 1;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: 'type' has been renamed to 'alias'
-type meow = 1;
-^^^^
-
-test.wgsl:1:13 error: invalid type alias
-type meow = 1;
-            ^
-)");
-}
-
-// TODO(crbug.com/tint/1812): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclTypeAliasMissingAssignment) {
-    EXPECT(
-        "type meow f32",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: 'type' has been renamed to 'alias'
-type meow f32
-^^^^
-
-test.wgsl:1:11 error: expected '=' for type alias
-type meow f32
-          ^^^
-)");
-}
-
-// TODO(crbug.com/tint/1812): DEPRECATED
-TEST_F(ParserImplErrorTest, DEPRECATED_GlobalDeclTypeAliasMissingSemicolon) {
-    EXPECT(
-        "type meow = f32",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: 'type' has been renamed to 'alias'
-type meow = f32
-^^^^
-
-test.wgsl:1:16 error: expected ';' for type alias
-type meow = f32
-               ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingGreaterThan) {
     EXPECT("var i : array<u32, 3;",
            R"(test.wgsl:1:14 error: expected ';' for variable declaration
@@ -979,7 +769,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrLocationInvalidValue) {
     EXPECT("@location(if) var i : i32;",
-           R"(test.wgsl:1:11 error: expected location expression
+           R"(test.wgsl:1:11 error: expected expression for location
 @location(if) var i : i32;
           ^^
 )");
@@ -1003,7 +793,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrIdInvalidValue) {
     EXPECT("@id(if) var i : i32;",
-           R"(test.wgsl:1:5 error: expected id expression
+           R"(test.wgsl:1:5 error: expected expression for id
 @id(if) var i : i32;
     ^^
 )");
@@ -1025,25 +815,6 @@
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBuiltinInvalidIdentifer) {
-    EXPECT("@builtin(1) var i : i32;",
-           R"(test.wgsl:1:10 error: expected builtin
-Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id'
-@builtin(1) var i : i32;
-         ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBuiltinInvalidValue) {
-    EXPECT("@builtin(frag_d3pth) var i : i32;",
-           R"(test.wgsl:1:10 error: expected builtin
-Did you mean 'frag_depth'?
-Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id'
-@builtin(frag_d3pth) var i : i32;
-         ^^^^^^^^^^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingMissingLParen) {
     EXPECT("@binding 1) var i : i32;",
            R"(test.wgsl:1:10 error: expected '(' for binding attribute
@@ -1062,7 +833,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingInvalidValue) {
     EXPECT("@binding(if) var i : i32;",
-           R"(test.wgsl:1:10 error: expected binding expression
+           R"(test.wgsl:1:10 error: expected expression for binding
 @binding(if) var i : i32;
          ^^
 )");
@@ -1086,7 +857,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingGroupValue) {
     EXPECT("@group(if) var i : i32;",
-           R"(test.wgsl:1:8 error: expected group expression
+           R"(test.wgsl:1:8 error: expected expression for group
 @group(if) var i : i32;
        ^^
 )");
@@ -1123,20 +894,11 @@
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclInvalidClass) {
-    EXPECT("var<fish> i : i32",
-           R"(test.wgsl:1:5 error: expected address space for variable declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup'
-var<fish> i : i32
-    ^^^^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclMissingGThan) {
     EXPECT("var<private i : i32",
-           R"(test.wgsl:1:13 error: expected '>' for variable declaration
+           R"(test.wgsl:1:4 error: missing closing '>' for variable declaration
 var<private i : i32
-            ^
+   ^
 )");
 }
 
@@ -1357,5 +1119,13 @@
            "fn fu\xD0nc() {}\n");
 }
 
+TEST_F(ParserImplErrorTest, Bug_Chromium_1417465) {
+    EXPECT("var<workgroup> vec4_data: array<mat4x4<f@32>, 256>;",
+           R"(test.wgsl:1:41 error: expected ',' for template argument list
+var<workgroup> vec4_data: array<mat4x4<f@32>, 256>;
+                                        ^
+)");
+}
+
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_error_resync_test.cc b/src/tint/reader/wgsl/parser_impl_error_resync_test.cc
index 9e37b51..f3e306a 100644
--- a/src/tint/reader/wgsl/parser_impl_error_resync_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_resync_test.cc
@@ -54,12 +54,9 @@
      ^
 
 test.wgsl:4:2 error: expected attribute
+Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
 @_ fn -> {}
  ^
-
-test.wgsl:4:7 error: expected identifier for function declaration
-@_ fn -> {}
-      ^^
 )");
 }
 
@@ -125,6 +122,7 @@
          ^^^^
 
 test.wgsl:7:6 error: expected attribute
+Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
     @- x : i32,
      ^
 )");
diff --git a/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc b/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
index 785d23c..ae43a0f 100644
--- a/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
@@ -51,7 +51,9 @@
     EXPECT_TRUE(attrs.errored);
     EXPECT_FALSE(attrs.matched);
     EXPECT_TRUE(attrs.value.IsEmpty());
-    EXPECT_EQ(p->error(), "1:2: expected attribute");
+    EXPECT_EQ(p->error(), R"(1:2: expected attribute
+Did you mean 'invariant'?
+Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size')");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
index 05151d0..5e96d8e 100644
--- a/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
@@ -100,7 +100,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:18: expected workgroup_size y parameter");
+    EXPECT_EQ(p->error(), "1:18: expected expression for workgroup_size");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_2Param) {
@@ -195,7 +195,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:20: expected workgroup_size z parameter");
+    EXPECT_EQ(p->error(), "1:20: expected expression for workgroup_size");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_3Param) {
@@ -323,7 +323,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:25: expected ')' for workgroup_size attribute");
+    EXPECT_EQ(p->error(), "1:1: workgroup_size expects at most 3 arguments, got 4");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_MissingLeftParam) {
@@ -353,7 +353,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:16: expected workgroup_size x parameter");
+    EXPECT_EQ(p->error(), "1:1: workgroup_size expects at least 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_Missing_X_Value) {
@@ -363,7 +363,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:16: expected workgroup_size x parameter");
+    EXPECT_EQ(p->error(), "1:16: expected expression for workgroup_size");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Y_Comma) {
@@ -383,7 +383,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:19: expected workgroup_size y parameter");
+    EXPECT_EQ(p->error(), "1:19: expected expression for workgroup_size");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Z_Comma) {
@@ -435,5 +435,17 @@
     EXPECT_EQ(func_attr->As<ast::StageAttribute>()->stage, ast::PipelineStage::kFragment);
 }
 
+TEST_F(ParserImplTest, Attribute_MustUse) {
+    auto p = parser("must_use");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    auto* func_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(func_attr, nullptr);
+    EXPECT_TRUE(func_attr->Is<ast::MustUseAttribute>());
+}
+
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_function_decl_test.cc b/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
index 2c26bac..3888326 100644
--- a/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
@@ -262,6 +262,23 @@
     EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
 }
 
+TEST_F(ParserImplTest, FunctionDecl_MustUse) {
+    auto p = parser("@must_use fn main() { return; }");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    ASSERT_TRUE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(f.errored);
+    EXPECT_TRUE(f.matched);
+    ASSERT_NE(f.value, nullptr);
+
+    auto& attributes = f->attributes;
+    ASSERT_EQ(attributes.Length(), 1u);
+    ASSERT_TRUE(attributes[0]->Is<ast::MustUseAttribute>());
+}
+
 TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) {
     auto p = parser("fn main() -> { }");
     auto attrs = p->attribute_list();
diff --git a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
index a14507c..697475e 100644
--- a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
@@ -132,41 +132,6 @@
     ast::CheckIdentifier(program.Symbols(), alias->type, "A");
 }
 
-// TODO(crbug.com/tint/1812): DEPRECATED
-TEST_F(ParserImplTest, DEPRECATED_GlobalDecl_TypeAlias) {
-    auto p = parser("type A = i32;");
-    p->global_decl();
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    auto program = p->program();
-    ASSERT_EQ(program.AST().TypeDecls().Length(), 1u);
-    ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Alias>());
-    ast::CheckIdentifier(program.Symbols(), program.AST().TypeDecls()[0]->As<ast::Alias>()->name,
-                         "A");
-}
-
-// TODO(crbug.com/tint/1812): DEPRECATED
-TEST_F(ParserImplTest, DEPRECATED_GlobalDecl_TypeAlias_StructIdent) {
-    auto p = parser(R"(struct A {
-  a : f32,
-}
-type B = A;)");
-    p->global_decl();
-    p->global_decl();
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    auto program = p->program();
-    ASSERT_EQ(program.AST().TypeDecls().Length(), 2u);
-    ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Struct>());
-    auto* str = program.AST().TypeDecls()[0]->As<ast::Struct>();
-    EXPECT_EQ(str->name->symbol, program.Symbols().Get("A"));
-
-    ASSERT_TRUE(program.AST().TypeDecls()[1]->Is<ast::Alias>());
-    auto* alias = program.AST().TypeDecls()[1]->As<ast::Alias>();
-    EXPECT_EQ(alias->name->symbol, program.Symbols().Get("B"));
-    ast::CheckIdentifier(program.Symbols(), alias->type, "A");
-}
-
 TEST_F(ParserImplTest, GlobalDecl_TypeAlias_MissingSemicolon) {
     auto p = parser("alias A = i32");
     p->global_decl();
@@ -174,16 +139,6 @@
     EXPECT_EQ(p->error(), "1:14: expected ';' for type alias");
 }
 
-// TODO(crbug.com/tint/1812): DEPRECATED
-TEST_F(ParserImplTest, DEPRECATED_GlobalDecl_TypeAlias_MissingSemicolon) {
-    auto p = parser("type A = i32");
-    p->global_decl();
-    ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(),
-              R"(1:1: use of deprecated language feature: 'type' has been renamed to 'alias'
-1:13: expected ';' for type alias)");
-}
-
 TEST_F(ParserImplTest, GlobalDecl_Function) {
     auto p = parser("fn main() { return; }");
     p->global_decl();
@@ -298,49 +253,5 @@
     EXPECT_EQ(sa->condition->source.range.end.column, 19u);
 }
 
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplTest, DEPRECATED_GlobalDecl_StaticAssert_WithParen) {
-    auto p = parser("static_assert(true);");
-    p->global_decl();
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    auto program = p->program();
-    ASSERT_EQ(program.AST().ConstAsserts().Length(), 1u);
-    auto* sa = program.AST().ConstAsserts()[0];
-    EXPECT_EQ(sa->source.range.begin.line, 1u);
-    EXPECT_EQ(sa->source.range.begin.column, 1u);
-    EXPECT_EQ(sa->source.range.end.line, 1u);
-    EXPECT_EQ(sa->source.range.end.column, 20u);
-
-    EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
-    EXPECT_EQ(sa->condition->source.range.begin.line, 1u);
-    EXPECT_EQ(sa->condition->source.range.begin.column, 15u);
-    EXPECT_EQ(sa->condition->source.range.end.line, 1u);
-    EXPECT_EQ(sa->condition->source.range.end.column, 19u);
-}
-
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplTest, DEPRECATED_GlobalDecl_StaticAssert_WithoutParen) {
-    auto p = parser("static_assert  true;");
-    p->global_decl();
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    auto program = p->program();
-    ASSERT_EQ(program.AST().ConstAsserts().Length(), 1u);
-    auto* sa = program.AST().ConstAsserts()[0];
-    EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
-
-    EXPECT_EQ(sa->source.range.begin.line, 1u);
-    EXPECT_EQ(sa->source.range.begin.column, 1u);
-    EXPECT_EQ(sa->source.range.end.line, 1u);
-    EXPECT_EQ(sa->source.range.end.column, 20u);
-
-    EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
-    EXPECT_EQ(sa->condition->source.range.begin.line, 1u);
-    EXPECT_EQ(sa->condition->source.range.begin.column, 16u);
-    EXPECT_EQ(sa->condition->source.range.end.line, 1u);
-    EXPECT_EQ(sa->condition->source.range.end.column, 20u);
-}
-
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
index 92272cc..a5de0a9 100644
--- a/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -31,10 +31,8 @@
     ASSERT_NE(var, nullptr);
 
     ast::CheckIdentifier(p->builder().Symbols(), var->name, "a");
-
     ast::CheckIdentifier(p->builder().Symbols(), var->type, "f32");
-
-    EXPECT_EQ(var->declared_address_space, type::AddressSpace::kPrivate);
+    ast::CheckIdentifier(p->builder().Symbols(), var->declared_address_space, "private");
 
     EXPECT_EQ(var->source.range.begin.line, 1u);
     EXPECT_EQ(var->source.range.begin.column, 14u);
@@ -58,8 +56,7 @@
 
     ast::CheckIdentifier(p->builder().Symbols(), var->name, "a");
     ast::CheckIdentifier(p->builder().Symbols(), var->type, "f32");
-
-    EXPECT_EQ(var->declared_address_space, type::AddressSpace::kPrivate);
+    ast::CheckIdentifier(p->builder().Symbols(), var->declared_address_space, "private");
 
     EXPECT_EQ(var->source.range.begin.line, 1u);
     EXPECT_EQ(var->source.range.begin.column, 14u);
@@ -83,11 +80,8 @@
     ASSERT_NE(var, nullptr);
 
     ast::CheckIdentifier(p->builder().Symbols(), var->name, "a");
-    ASSERT_NE(var->type, nullptr);
-
     ast::CheckIdentifier(p->builder().Symbols(), var->type, "f32");
-
-    EXPECT_EQ(var->declared_address_space, type::AddressSpace::kUniform);
+    ast::CheckIdentifier(p->builder().Symbols(), var->declared_address_space, "uniform");
 
     EXPECT_EQ(var->source.range.begin.line, 1u);
     EXPECT_EQ(var->source.range.begin.column, 36u);
@@ -116,10 +110,8 @@
     ASSERT_NE(var, nullptr);
 
     ast::CheckIdentifier(p->builder().Symbols(), var->name, "a");
-    ASSERT_NE(var->type, nullptr);
     ast::CheckIdentifier(p->builder().Symbols(), var->type, "f32");
-
-    EXPECT_EQ(var->declared_address_space, type::AddressSpace::kUniform);
+    ast::CheckIdentifier(p->builder().Symbols(), var->declared_address_space, "uniform");
 
     EXPECT_EQ(var->source.range.begin.line, 1u);
     EXPECT_EQ(var->source.range.begin.column, 36u);
@@ -146,7 +138,7 @@
     EXPECT_NE(e.value, nullptr);
 
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:10: expected binding expression");
+    EXPECT_EQ(p->error(), "1:2: binding expects 1 argument");
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
@@ -162,19 +154,5 @@
     EXPECT_EQ(p->error(), "1:24: missing initializer for 'var' declaration");
 }
 
-TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {
-    auto p = parser("var<invalid> a : f32;");
-    auto attrs = p->attribute_list();
-    EXPECT_FALSE(attrs.errored);
-    EXPECT_FALSE(attrs.matched);
-    auto e = p->global_variable_decl(attrs.value);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_TRUE(e.errored);
-    EXPECT_FALSE(e.matched);
-    EXPECT_EQ(e.value, nullptr);
-    EXPECT_EQ(p->error(), R"(1:5: expected address space for variable declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
-
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_param_list_test.cc b/src/tint/reader/wgsl/parser_impl_param_list_test.cc
index 696d791..eb4db45 100644
--- a/src/tint/reader/wgsl/parser_impl_param_list_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_param_list_test.cc
@@ -102,7 +102,8 @@
     auto attrs_0 = e.value[0]->attributes;
     ASSERT_EQ(attrs_0.Length(), 1u);
     EXPECT_TRUE(attrs_0[0]->Is<ast::BuiltinAttribute>());
-    EXPECT_EQ(attrs_0[0]->As<ast::BuiltinAttribute>()->builtin, builtin::BuiltinValue::kPosition);
+    ast::CheckIdentifier(p->builder().Symbols(), attrs_0[0]->As<ast::BuiltinAttribute>()->builtin,
+                         "position");
 
     ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
     ASSERT_EQ(e.value[0]->source.range.begin.column, 20u);
diff --git a/src/tint/reader/wgsl/parser_impl_require_directive_test.cc b/src/tint/reader/wgsl/parser_impl_require_directive_test.cc
new file mode 100644
index 0000000..d3cf17c
--- /dev/null
+++ b/src/tint/reader/wgsl/parser_impl_require_directive_test.cc
@@ -0,0 +1,71 @@
+// Copyright 2023 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/tint/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+using RequiresDirectiveTest = ParserImplTest;
+
+// Test a valid require directive.
+// There currently are no valid require directives
+TEST_F(RequiresDirectiveTest, DISABLED_Valid) {
+    auto p = parser("requires <sometime>;");
+    p->requires_directive();
+    EXPECT_FALSE(p->has_error()) << p->error();
+}
+
+// Test an unknown require identifier.
+TEST_F(RequiresDirectiveTest, InvalidIdentifier) {
+    auto p = parser("requires NotAValidRequireName;");
+    p->requires_directive();
+    // Error when unknown require found
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), R"(1:10: feature 'NotAValidRequireName' is not supported)");
+}
+
+// Test the special error message when require are used with parenthesis.
+TEST_F(RequiresDirectiveTest, ParenthesisSpecialCase) {
+    auto p = parser("requires(Something);");
+    p->translation_unit();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: requires directives don't take parenthesis");
+}
+
+// Test using invalid tokens in an require directive.
+TEST_F(RequiresDirectiveTest, InvalidTokens) {
+    {
+        auto p = parser("requires <Something;");
+        p->translation_unit();
+        EXPECT_TRUE(p->has_error());
+        EXPECT_EQ(p->error(), R"(1:10: invalid feature name for requires)");
+    }
+    {
+        auto p = parser("requires =;");
+        p->translation_unit();
+        EXPECT_TRUE(p->has_error());
+        EXPECT_EQ(p->error(), R"(1:10: invalid feature name for requires)");
+    }
+
+    {
+        auto p = parser("requires;");
+        p->translation_unit();
+        EXPECT_TRUE(p->has_error());
+        EXPECT_EQ(p->error(), R"(1:9: missing feature names in requires directive)");
+    }
+}
+
+}  // namespace
+}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc b/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
index c20302d..647bb44 100644
--- a/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
@@ -152,7 +152,6 @@
                                          "inout",
                                          "instanceof",
                                          "interface",
-                                         "invariant",
                                          "layout",
                                          "lowp",
                                          "macro",
@@ -194,7 +193,6 @@
                                          "regardless",
                                          "register",
                                          "reinterpret_cast",
-                                         "requires",
                                          "resource",
                                          "restrict",
                                          "self",
@@ -205,6 +203,7 @@
                                          "smooth",
                                          "snorm",
                                          "static",
+                                         "static_assert",
                                          "static_cast",
                                          "std",
                                          "subroutine",
diff --git a/src/tint/reader/wgsl/parser_impl_statement_test.cc b/src/tint/reader/wgsl/parser_impl_statement_test.cc
index 7371b81..634bfb4 100644
--- a/src/tint/reader/wgsl/parser_impl_statement_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_statement_test.cc
@@ -314,50 +314,6 @@
     EXPECT_EQ(sa->condition->source.range.end.column, 19u);
 }
 
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplTest, DEPRECATED_Statement_StaticAssert_WithParen) {
-    auto p = parser("static_assert(true);");
-    auto e = p->statement();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(e.matched);
-    EXPECT_FALSE(e.errored);
-
-    auto* sa = As<ast::ConstAssert>(e.value);
-    ASSERT_NE(sa, nullptr);
-    EXPECT_EQ(sa->source.range.begin.line, 1u);
-    EXPECT_EQ(sa->source.range.begin.column, 1u);
-    EXPECT_EQ(sa->source.range.end.line, 1u);
-    EXPECT_EQ(sa->source.range.end.column, 20u);
-
-    EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
-    EXPECT_EQ(sa->condition->source.range.begin.line, 1u);
-    EXPECT_EQ(sa->condition->source.range.begin.column, 15u);
-    EXPECT_EQ(sa->condition->source.range.end.line, 1u);
-    EXPECT_EQ(sa->condition->source.range.end.column, 19u);
-}
-
-// TODO(crbug.com/tint/1807)
-TEST_F(ParserImplTest, DEPRECATED_Statement_StaticAssert_WithoutParen) {
-    auto p = parser("static_assert  true;");
-    auto e = p->statement();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(e.matched);
-    EXPECT_FALSE(e.errored);
-
-    auto* sa = As<ast::ConstAssert>(e.value);
-    ASSERT_NE(sa, nullptr);
-    EXPECT_EQ(sa->source.range.begin.line, 1u);
-    EXPECT_EQ(sa->source.range.begin.column, 1u);
-    EXPECT_EQ(sa->source.range.end.line, 1u);
-    EXPECT_EQ(sa->source.range.end.column, 20u);
-
-    EXPECT_TRUE(sa->condition->Is<ast::BoolLiteralExpression>());
-    EXPECT_EQ(sa->condition->source.range.begin.line, 1u);
-    EXPECT_EQ(sa->condition->source.range.begin.column, 16u);
-    EXPECT_EQ(sa->condition->source.range.end.line, 1u);
-    EXPECT_EQ(sa->condition->source.range.end.column, 20u);
-}
-
 TEST_F(ParserImplTest, Statement_UnexpectedAttributes) {
     auto p = parser("@diagnostic(off, derivative_uniformity) return;");
     auto e = p->statement();
diff --git a/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc b/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
index 051104b..4f07a65 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
@@ -46,7 +46,7 @@
     EXPECT_TRUE(attrs.errored);
     EXPECT_FALSE(attrs.matched);
     EXPECT_TRUE(attrs.value.IsEmpty());
-    EXPECT_EQ(p->error(), "1:11: expected location expression");
+    EXPECT_EQ(p->error(), "1:2: location expects 1 argument");
 }
 
 TEST_F(ParserImplTest, AttributeDecl_MissingParenRight) {
diff --git a/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc b/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
index d01c266..a4fbe2c 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
@@ -66,7 +66,7 @@
     auto m = p->expect_struct_body_decl();
     ASSERT_TRUE(p->has_error());
     ASSERT_TRUE(m.errored);
-    EXPECT_EQ(p->error(), "3:10: expected align expression");
+    EXPECT_EQ(p->error(), "3:10: expected expression for align");
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_InvalidSize) {
@@ -77,7 +77,7 @@
     auto m = p->expect_struct_body_decl();
     ASSERT_TRUE(p->has_error());
     ASSERT_TRUE(m.errored);
-    EXPECT_EQ(p->error(), "3:9: expected size expression");
+    EXPECT_EQ(p->error(), "3:9: expected expression for size");
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) {
diff --git a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
index 0417f7c..366d66f 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
@@ -44,7 +44,7 @@
     EXPECT_TRUE(p->has_error()) << p->error();
     EXPECT_TRUE(attrs.errored);
     EXPECT_FALSE(attrs.matched);
-    EXPECT_EQ(p->error(), "1:7: expected size expression");
+    EXPECT_EQ(p->error(), "1:7: expected expression for size");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
index 7abdcd5..30834ad 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
@@ -104,7 +104,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:6: expected size expression");
+    EXPECT_EQ(p->error(), "1:1: size expects 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Size_MissingInvalid) {
@@ -114,7 +114,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:6: expected size expression");
+    EXPECT_EQ(p->error(), "1:6: expected expression for size");
 }
 
 TEST_F(ParserImplTest, Attribute_Align) {
@@ -209,7 +209,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:7: expected align expression");
+    EXPECT_EQ(p->error(), "1:1: align expects 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Align_ExpressionInvalid) {
diff --git a/src/tint/reader/wgsl/parser_impl_struct_member_test.cc b/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
index 3c27a9f..0af0ba2 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
@@ -115,7 +115,7 @@
     ASSERT_EQ(m.value, nullptr);
 
     ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:7: expected size expression");
+    EXPECT_EQ(p->error(), "1:7: expected expression for size");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_type_alias_test.cc b/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
index 1c2b4fe..1aa8bf9 100644
--- a/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
@@ -19,7 +19,7 @@
 namespace {
 
 TEST_F(ParserImplTest, TypeDecl_ParsesType) {
-    auto p = parser("type a = i32");
+    auto p = parser("alias a = i32");
 
     auto t = p->type_alias_decl();
     EXPECT_FALSE(p->has_error());
@@ -29,11 +29,11 @@
     ASSERT_TRUE(t->Is<ast::Alias>());
     auto* alias = t->As<ast::Alias>();
     ast::CheckIdentifier(p->builder().Symbols(), alias->type, "i32");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 13u}}));
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 14u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Parses_Ident) {
-    auto p = parser("type a = B");
+    auto p = parser("alias a = B");
 
     auto t = p->type_alias_decl();
     EXPECT_FALSE(p->has_error());
@@ -44,7 +44,7 @@
     auto* alias = t.value->As<ast::Alias>();
     ast::CheckIdentifier(p->builder().Symbols(), alias->name, "a");
     ast::CheckIdentifier(p->builder().Symbols(), alias->type, "B");
-    EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 11u}}));
+    EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 12u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Unicode_Parses_Ident) {
@@ -52,7 +52,7 @@
         "\xf0\x9d\x93\xb6\xf0\x9d\x94\x82\x5f\xf0\x9d\x93\xbd\xf0\x9d\x94\x82\xf0"
         "\x9d\x93\xb9\xf0\x9d\x93\xae";
 
-    auto p = parser("type " + ident + " = i32");
+    auto p = parser("alias " + ident + " = i32");
 
     auto t = p->type_alias_decl();
     EXPECT_FALSE(p->has_error());
@@ -63,43 +63,37 @@
     auto* alias = t.value->As<ast::Alias>();
     ast::CheckIdentifier(p->builder().Symbols(), alias->name, ident);
     ast::CheckIdentifier(p->builder().Symbols(), alias->type, "i32");
-    EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 37u}}));
+    EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 38u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
-    auto p = parser("type = i32");
+    auto p = parser("alias = i32");
     auto t = p->type_alias_decl();
     EXPECT_TRUE(t.errored);
     EXPECT_FALSE(t.matched);
     EXPECT_TRUE(p->has_error());
     EXPECT_EQ(t.value, nullptr);
-    EXPECT_EQ(p->error(),
-              R"(1:1: use of deprecated language feature: 'type' has been renamed to 'alias'
-1:6: expected identifier for type alias)");
+    EXPECT_EQ(p->error(), R"(1:7: expected identifier for type alias)");
 }
 
 TEST_F(ParserImplTest, TypeDecl_InvalidIdent) {
-    auto p = parser("type 123 = i32");
+    auto p = parser("alias 123 = i32");
     auto t = p->type_alias_decl();
     EXPECT_TRUE(t.errored);
     EXPECT_FALSE(t.matched);
     EXPECT_TRUE(p->has_error());
     EXPECT_EQ(t.value, nullptr);
-    EXPECT_EQ(p->error(),
-              R"(1:1: use of deprecated language feature: 'type' has been renamed to 'alias'
-1:6: expected identifier for type alias)");
+    EXPECT_EQ(p->error(), R"(1:7: expected identifier for type alias)");
 }
 
 TEST_F(ParserImplTest, TypeDecl_MissingEqual) {
-    auto p = parser("type a i32");
+    auto p = parser("alias a i32");
     auto t = p->type_alias_decl();
     EXPECT_TRUE(t.errored);
     EXPECT_FALSE(t.matched);
     EXPECT_TRUE(p->has_error());
     EXPECT_EQ(t.value, nullptr);
-    EXPECT_EQ(p->error(),
-              R"(1:1: use of deprecated language feature: 'type' has been renamed to 'alias'
-1:8: expected '=' for type alias)");
+    EXPECT_EQ(p->error(), R"(1:9: expected '=' for type alias)");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_type_decl_test.cc b/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
index b40d887..25e60e0 100644
--- a/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
@@ -137,7 +137,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:6: expected expression");
+    ASSERT_EQ(p->error(), "1:6: expected expression for type template argument list");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          VecMissingType,
@@ -211,7 +211,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:5: expected expression)");
+    ASSERT_EQ(p->error(), R"(1:5: expected expression for type template argument list)");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
@@ -221,7 +221,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:5: expected expression)");
+    ASSERT_EQ(p->error(), R"(1:5: expected expression for type template argument list)");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Atomic) {
@@ -256,7 +256,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:8: expected expression");
+    ASSERT_EQ(p->error(), "1:8: expected expression for type template argument list");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_AbstractIntLiteralSize) {
@@ -431,7 +431,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:8: expected expression");
+    ASSERT_EQ(p->error(), "1:8: expected expression for type template argument list");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          MatrixMissingType,
diff --git a/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc b/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc
index 163396e..07775c5 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_attribute_list_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/ast/test_helper.h"
 #include "src/tint/reader/wgsl/parser_impl_test_helper.h"
 
 namespace tint::reader::wgsl {
@@ -38,7 +39,8 @@
     EXPECT_EQ(exp->value, 4u);
 
     ASSERT_TRUE(attr_1->Is<ast::BuiltinAttribute>());
-    EXPECT_EQ(attr_1->As<ast::BuiltinAttribute>()->builtin, builtin::BuiltinValue::kPosition);
+    ast::CheckIdentifier(p->builder().Symbols(), attr_1->As<ast::BuiltinAttribute>()->builtin,
+                         "position");
 }
 
 TEST_F(ParserImplTest, AttributeList_Invalid) {
@@ -48,30 +50,10 @@
     EXPECT_TRUE(attrs.errored);
     EXPECT_FALSE(attrs.matched);
     EXPECT_TRUE(attrs.value.IsEmpty());
-    EXPECT_EQ(p->error(), R"(1:2: expected attribute)");
+    EXPECT_EQ(p->error(), R"(1:2: expected attribute
+Did you mean 'invariant'?
+Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size')");
 }
 
-TEST_F(ParserImplTest, AttributeList_InvalidValue) {
-    auto p = parser("@builtin(invalid)");
-    auto attrs = p->attribute_list();
-    EXPECT_TRUE(p->has_error());
-    EXPECT_TRUE(attrs.errored);
-    EXPECT_FALSE(attrs.matched);
-    EXPECT_TRUE(attrs.value.IsEmpty());
-    EXPECT_EQ(p->error(), R"(1:10: expected builtin
-Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
-}
-
-TEST_F(ParserImplTest, AttributeList_InvalidValueSuggest) {
-    auto p = parser("@builtin(instanceindex)");
-    auto attrs = p->attribute_list();
-    EXPECT_TRUE(p->has_error());
-    EXPECT_TRUE(attrs.errored);
-    EXPECT_FALSE(attrs.matched);
-    EXPECT_TRUE(attrs.value.IsEmpty());
-    EXPECT_EQ(p->error(), R"(1:10: expected builtin
-Did you mean 'instance_index'?
-Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
-}
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
index bc0c2c9..2ca7da4 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/reader/wgsl/parser_impl_test_helper.h"
 
 namespace tint::reader::wgsl {
@@ -103,7 +105,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:4: expected id expression");
+    EXPECT_EQ(p->error(), "1:1: id expects 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Id_MissingInvalid) {
@@ -113,7 +115,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:4: expected id expression");
+    EXPECT_EQ(p->error(), "1:4: expected expression for id");
 }
 
 TEST_F(ParserImplTest, Attribute_Location) {
@@ -202,7 +204,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:10: expected location expression");
+    EXPECT_EQ(p->error(), "1:1: location expects 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Location_MissingInvalid) {
@@ -212,23 +214,14 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:10: expected location expression");
+    EXPECT_EQ(p->error(), "1:10: expected expression for location");
 }
 
-struct BuiltinData {
-    const char* input;
-    builtin::BuiltinValue result;
-};
-inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-    out << std::string(data.input);
-    return out;
-}
-
-class BuiltinTest : public ParserImplTestWithParam<BuiltinData> {};
+class BuiltinTest : public ParserImplTestWithParam<builtin::BuiltinValue> {};
 
 TEST_P(BuiltinTest, Attribute_Builtin) {
-    auto params = GetParam();
-    auto p = parser(std::string("builtin(") + params.input + ")");
+    auto str = utils::ToString(GetParam());
+    auto p = parser("builtin(" + str + ")");
 
     auto attr = p->attribute();
     EXPECT_TRUE(attr.matched);
@@ -240,11 +233,11 @@
     ASSERT_TRUE(var_attr->Is<ast::BuiltinAttribute>());
 
     auto* builtin = var_attr->As<ast::BuiltinAttribute>();
-    EXPECT_EQ(builtin->builtin, params.result);
+    ast::CheckIdentifier(p->builder().Symbols(), builtin->builtin, str);
 }
 TEST_P(BuiltinTest, Attribute_Builtin_TrailingComma) {
-    auto params = GetParam();
-    auto p = parser(std::string("builtin(") + params.input + ",)");
+    auto str = utils::ToString(GetParam());
+    auto p = parser("builtin(" + str + ",)");
 
     auto attr = p->attribute();
     EXPECT_TRUE(attr.matched);
@@ -256,24 +249,22 @@
     ASSERT_TRUE(var_attr->Is<ast::BuiltinAttribute>());
 
     auto* builtin = var_attr->As<ast::BuiltinAttribute>();
-    EXPECT_EQ(builtin->builtin, params.result);
+    ast::CheckIdentifier(p->builder().Symbols(), builtin->builtin, str);
 }
-INSTANTIATE_TEST_SUITE_P(
-    ParserImplTest,
-    BuiltinTest,
-    testing::Values(BuiltinData{"position", builtin::BuiltinValue::kPosition},
-                    BuiltinData{"vertex_index", builtin::BuiltinValue::kVertexIndex},
-                    BuiltinData{"instance_index", builtin::BuiltinValue::kInstanceIndex},
-                    BuiltinData{"front_facing", builtin::BuiltinValue::kFrontFacing},
-                    BuiltinData{"frag_depth", builtin::BuiltinValue::kFragDepth},
-                    BuiltinData{"local_invocation_id", builtin::BuiltinValue::kLocalInvocationId},
-                    BuiltinData{"local_invocation_index",
-                                builtin::BuiltinValue::kLocalInvocationIndex},
-                    BuiltinData{"global_invocation_id", builtin::BuiltinValue::kGlobalInvocationId},
-                    BuiltinData{"workgroup_id", builtin::BuiltinValue::kWorkgroupId},
-                    BuiltinData{"num_workgroups", builtin::BuiltinValue::kNumWorkgroups},
-                    BuiltinData{"sample_index", builtin::BuiltinValue::kSampleIndex},
-                    BuiltinData{"sample_mask", builtin::BuiltinValue::kSampleMask}));
+INSTANTIATE_TEST_SUITE_P(ParserImplTest,
+                         BuiltinTest,
+                         testing::Values(builtin::BuiltinValue::kPosition,
+                                         builtin::BuiltinValue::kVertexIndex,
+                                         builtin::BuiltinValue::kInstanceIndex,
+                                         builtin::BuiltinValue::kFrontFacing,
+                                         builtin::BuiltinValue::kFragDepth,
+                                         builtin::BuiltinValue::kLocalInvocationId,
+                                         builtin::BuiltinValue::kLocalInvocationIndex,
+                                         builtin::BuiltinValue::kGlobalInvocationId,
+                                         builtin::BuiltinValue::kWorkgroupId,
+                                         builtin::BuiltinValue::kNumWorkgroups,
+                                         builtin::BuiltinValue::kSampleIndex,
+                                         builtin::BuiltinValue::kSampleMask));
 
 TEST_F(ParserImplTest, Attribute_Builtin_MissingLeftParen) {
     auto p = parser("builtin position)");
@@ -302,42 +293,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:9: expected builtin
-Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
-}
-
-TEST_F(ParserImplTest, Attribute_Builtin_InvalidValue) {
-    auto p = parser("builtin(other_thingy)");
-    auto attr = p->attribute();
-    EXPECT_FALSE(attr.matched);
-    EXPECT_TRUE(attr.errored);
-    EXPECT_EQ(attr.value, nullptr);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:9: expected builtin
-Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
-}
-
-TEST_F(ParserImplTest, Attribute_Builtin_InvalidValueSuggest) {
-    auto p = parser("builtin(front_face)");
-    auto attr = p->attribute();
-    EXPECT_FALSE(attr.matched);
-    EXPECT_TRUE(attr.errored);
-    EXPECT_EQ(attr.value, nullptr);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:9: expected builtin
-Did you mean 'front_facing'?
-Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
-}
-
-TEST_F(ParserImplTest, Attribute_Builtin_MissingInvalid) {
-    auto p = parser("builtin(3)");
-    auto attr = p->attribute();
-    EXPECT_FALSE(attr.matched);
-    EXPECT_TRUE(attr.errored);
-    EXPECT_EQ(attr.value, nullptr);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:9: expected builtin
-Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
+    EXPECT_EQ(p->error(), "1:1: builtin expects 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Flat) {
@@ -352,8 +308,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kFlat);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kUndefined);
+    ast::CheckIdentifier(p->builder().Symbols(), interp->type, "flat");
+    EXPECT_EQ(interp->sampling, nullptr);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Single_TrailingComma) {
@@ -368,8 +324,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kFlat);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kUndefined);
+    ast::CheckIdentifier(p->builder().Symbols(), interp->type, "flat");
+    EXPECT_EQ(interp->sampling, nullptr);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Single_DoubleTrailingComma) {
@@ -379,8 +335,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:18: expected interpolation sampling
-Possible values: 'center', 'centroid', 'sample')");
+    EXPECT_EQ(p->error(), "1:18: expected expression for interpolate");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Center) {
@@ -395,8 +350,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCenter);
+    ast::CheckIdentifier(p->builder().Symbols(), interp->type, "perspective");
+    ast::CheckIdentifier(p->builder().Symbols(), interp->sampling, "center");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Double_TrailingComma) {
@@ -411,8 +366,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCenter);
+    ast::CheckIdentifier(p->builder().Symbols(), interp->type, "perspective");
+    ast::CheckIdentifier(p->builder().Symbols(), interp->sampling, "center");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Centroid) {
@@ -427,8 +382,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCentroid);
+    ast::CheckIdentifier(p->builder().Symbols(), interp->type, "perspective");
+    ast::CheckIdentifier(p->builder().Symbols(), interp->sampling, "centroid");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Linear_Sample) {
@@ -443,8 +398,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kLinear);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kSample);
+    ast::CheckIdentifier(p->builder().Symbols(), interp->type, "linear");
+    ast::CheckIdentifier(p->builder().Symbols(), interp->sampling, "sample");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_MissingLeftParen) {
@@ -474,31 +429,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:13: expected interpolation type
-Possible values: 'flat', 'linear', 'perspective')");
-}
-
-TEST_F(ParserImplTest, Attribute_Interpolate_InvalidFirstValue) {
-    auto p = parser("interpolate(other_thingy)");
-    auto attr = p->attribute();
-    EXPECT_FALSE(attr.matched);
-    EXPECT_TRUE(attr.errored);
-    EXPECT_EQ(attr.value, nullptr);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:13: expected interpolation type
-Possible values: 'flat', 'linear', 'perspective')");
-}
-
-TEST_F(ParserImplTest, Attribute_Interpolate_InvalidSecondValue) {
-    auto p = parser("interpolate(perspective, nope)");
-    auto attr = p->attribute();
-    EXPECT_FALSE(attr.matched);
-    EXPECT_TRUE(attr.errored);
-    EXPECT_EQ(attr.value, nullptr);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:26: expected interpolation sampling
-Did you mean 'sample'?
-Possible values: 'center', 'centroid', 'sample')");
+    EXPECT_EQ(p->error(), "1:1: interpolate expects at least 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Binding) {
@@ -589,7 +520,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:9: expected binding expression");
+    EXPECT_EQ(p->error(), "1:1: binding expects 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Binding_MissingInvalid) {
@@ -599,7 +530,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:9: expected binding expression");
+    EXPECT_EQ(p->error(), "1:9: expected expression for binding");
 }
 
 TEST_F(ParserImplTest, Attribute_group) {
@@ -690,7 +621,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:7: expected group expression");
+    EXPECT_EQ(p->error(), "1:1: group expects 1 argument");
 }
 
 TEST_F(ParserImplTest, Attribute_Group_MissingInvalid) {
@@ -700,7 +631,7 @@
     EXPECT_TRUE(attr.errored);
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:7: expected group expression");
+    EXPECT_EQ(p->error(), "1:7: expected expression for group");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc b/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
index 9138d55..993ecb0 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
@@ -84,8 +84,7 @@
     EXPECT_EQ(v->name, "my_var");
 
     ast::CheckIdentifier(p->builder().Symbols(), v->type, "f32");
-
-    EXPECT_EQ(v->address_space, type::AddressSpace::kPrivate);
+    ast::CheckIdentifier(p->builder().Symbols(), v->address_space, "private");
 
     EXPECT_EQ(v->source.range.begin.line, 1u);
     EXPECT_EQ(v->source.range.begin.column, 14u);
@@ -102,20 +101,7 @@
     EXPECT_EQ(v->name, "my_var");
 
     ast::CheckIdentifier(p->builder().Symbols(), v->type, "f32");
-
-    EXPECT_EQ(v->address_space, type::AddressSpace::kPushConstant);
-}
-
-TEST_F(ParserImplTest, VariableDecl_InvalidAddressSpace) {
-    auto p = parser("var<unknown> my_var : f32");
-    auto v = p->variable_decl();
-    EXPECT_FALSE(v.matched);
-    EXPECT_TRUE(v.errored);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(),
-              R"(1:5: expected address space for variable declaration
-Did you mean 'uniform'?
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
+    ast::CheckIdentifier(p->builder().Symbols(), v->address_space, "push_constant");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc b/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
index 111f207..3c25d85 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/ast/test_helper.h"
 #include "src/tint/reader/wgsl/parser_impl_test_helper.h"
 
 namespace tint::reader::wgsl {
@@ -19,8 +20,8 @@
 
 struct VariableStorageData {
     const char* input;
-    type::AddressSpace address_space;
-    type::Access access;
+    builtin::AddressSpace address_space;
+    builtin::Access access;
 };
 inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
     out << std::string(data.input);
@@ -31,14 +32,23 @@
 
 TEST_P(VariableQualifierTest, ParsesAddressSpace) {
     auto params = GetParam();
-    auto p = parser(std::string("<") + params.input + ">");
+    auto p = parser(std::string("var<") + params.input + "> name");
 
-    auto sc = p->variable_qualifier();
+    auto sc = p->variable_decl();
     EXPECT_FALSE(p->has_error());
     EXPECT_FALSE(sc.errored);
     EXPECT_TRUE(sc.matched);
-    EXPECT_EQ(sc->address_space, params.address_space);
-    EXPECT_EQ(sc->access, params.access);
+    if (params.address_space != builtin::AddressSpace::kUndefined) {
+        ast::CheckIdentifier(p->builder().Symbols(), sc->address_space,
+                             utils::ToString(params.address_space));
+    } else {
+        EXPECT_EQ(sc->address_space, nullptr);
+    }
+    if (params.access != builtin::Access::kUndefined) {
+        ast::CheckIdentifier(p->builder().Symbols(), sc->access, utils::ToString(params.access));
+    } else {
+        EXPECT_EQ(sc->access, nullptr);
+    }
 
     auto& t = p->next();
     EXPECT_TRUE(t.IsEof());
@@ -46,35 +56,30 @@
 INSTANTIATE_TEST_SUITE_P(
     ParserImplTest,
     VariableQualifierTest,
-    testing::Values(
-        VariableStorageData{"uniform", type::AddressSpace::kUniform, type::Access::kUndefined},
-        VariableStorageData{"workgroup", type::AddressSpace::kWorkgroup, type::Access::kUndefined},
-        VariableStorageData{"storage", type::AddressSpace::kStorage, type::Access::kUndefined},
-        VariableStorageData{"private", type::AddressSpace::kPrivate, type::Access::kUndefined},
-        VariableStorageData{"function", type::AddressSpace::kFunction, type::Access::kUndefined},
-        VariableStorageData{"storage, read", type::AddressSpace::kStorage, type::Access::kRead},
-        VariableStorageData{"storage, write", type::AddressSpace::kStorage, type::Access::kWrite},
-        VariableStorageData{"storage, read_write", type::AddressSpace::kStorage,
-                            type::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(), R"(1:2: expected address space for variable declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
+    testing::Values(VariableStorageData{"uniform", builtin::AddressSpace::kUniform,
+                                        builtin::Access::kUndefined},
+                    VariableStorageData{"workgroup", builtin::AddressSpace::kWorkgroup,
+                                        builtin::Access::kUndefined},
+                    VariableStorageData{"storage", builtin::AddressSpace::kStorage,
+                                        builtin::Access::kUndefined},
+                    VariableStorageData{"private", builtin::AddressSpace::kPrivate,
+                                        builtin::Access::kUndefined},
+                    VariableStorageData{"function", builtin::AddressSpace::kFunction,
+                                        builtin::Access::kUndefined},
+                    VariableStorageData{"storage, read", builtin::AddressSpace::kStorage,
+                                        builtin::Access::kRead},
+                    VariableStorageData{"storage, write", builtin::AddressSpace::kStorage,
+                                        builtin::Access::kWrite},
+                    VariableStorageData{"storage, read_write", builtin::AddressSpace::kStorage,
+                                        builtin::Access::kReadWrite}));
 
 TEST_F(ParserImplTest, VariableQualifier_Empty) {
-    auto p = parser("<>");
-    auto sc = p->variable_qualifier();
+    auto p = parser("var<> name");
+    auto sc = p->variable_decl();
     EXPECT_TRUE(p->has_error());
     EXPECT_TRUE(sc.errored);
     EXPECT_FALSE(sc.matched);
-    EXPECT_EQ(p->error(), R"(1:2: expected address space for variable declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
+    EXPECT_EQ(p->error(), R"(1:5: expected expression for 'var' address space)");
 }
 
 TEST_F(ParserImplTest, VariableQualifier_MissingLessThan) {
@@ -105,7 +110,7 @@
     EXPECT_TRUE(p->has_error());
     EXPECT_TRUE(sc.errored);
     EXPECT_FALSE(sc.matched);
-    EXPECT_EQ(p->error(), "1:9: expected '>' for variable declaration");
+    EXPECT_EQ(p->error(), "1:1: missing closing '>' for variable declaration");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/token.cc b/src/tint/reader/wgsl/token.cc
index 3bc2a0d..e133dfc 100644
--- a/src/tint/reader/wgsl/token.cc
+++ b/src/tint/reader/wgsl/token.cc
@@ -181,16 +181,14 @@
             return "override";
         case Token::Type::kReturn:
             return "return";
-        case Token::Type::kStaticAssert:
-            return "static_assert";
+        case Token::Type::kRequires:
+            return "requires";
         case Token::Type::kStruct:
             return "struct";
         case Token::Type::kSwitch:
             return "switch";
         case Token::Type::kTrue:
             return "true";
-        case Token::Type::kType:
-            return "type";
         case Token::Type::kVar:
             return "var";
         case Token::Type::kWhile:
diff --git a/src/tint/reader/wgsl/token.h b/src/tint/reader/wgsl/token.h
index c2f08a7..222f28e 100644
--- a/src/tint/reader/wgsl/token.h
+++ b/src/tint/reader/wgsl/token.h
@@ -193,16 +193,14 @@
         kOverride,
         /// A 'return'
         kReturn,
-        /// A 'static_assert'
-        kStaticAssert,
+        /// A 'requires'
+        kRequires,
         /// A 'struct'
         kStruct,
         /// A 'switch'
         kSwitch,
         /// A 'true'
         kTrue,
-        /// A 'type'
-        kType,
         /// A 'var'
         kVar,
         /// A 'while'
diff --git a/src/tint/resolver/address_space_layout_validation_test.cc b/src/tint/resolver/address_space_layout_validation_test.cc
index 041e566..79e2781 100644
--- a/src/tint/resolver/address_space_layout_validation_test.cc
+++ b/src/tint/resolver/address_space_layout_validation_test.cc
@@ -39,7 +39,7 @@
                   Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_i)}),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("S"), type::AddressSpace::kStorage, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("S"), builtin::AddressSpace::kStorage, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -69,7 +69,7 @@
                   Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(4_i)}),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("S"), type::AddressSpace::kStorage, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("S"), builtin::AddressSpace::kStorage, Group(0_a),
               Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -100,7 +100,7 @@
                   Member(Source{{56, 78}}, "inner", ty("Inner")),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -144,7 +144,7 @@
                   Member(Source{{56, 78}}, "inner", ty("Inner"), utils::Vector{MemberAlign(16_i)}),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -169,7 +169,7 @@
                   Member(Source{{56, 78}}, "inner", ty("Inner")),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -202,7 +202,7 @@
                   Member(Source{{34, 56}}, "inner", ty("Inner"), utils::Vector{MemberAlign(16_i)}),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -234,7 +234,7 @@
                   Member(Source{{78, 90}}, "scalar", ty.i32()),
               });
 
-    GlobalVar(Source{{22, 24}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{22, 24}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -286,7 +286,7 @@
                   Member(Source{{78, 90}}, "scalar", ty.i32()),
               });
 
-    GlobalVar(Source{{22, 24}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{22, 24}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -334,7 +334,7 @@
                   Member(Source{{78, 90}}, "scalar", ty.i32(), utils::Vector{MemberAlign(16_i)}),
               });
 
-    GlobalVar(Source{{22, 34}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{22, 34}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -355,7 +355,7 @@
                                              Member("s", ty.f32()),
                                          });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("ScalarPackedAtEndOfVec3"), type::AddressSpace::kUniform,
+    GlobalVar(Source{{78, 90}}, "a", ty("ScalarPackedAtEndOfVec3"), builtin::AddressSpace::kUniform,
               Group(0_a), Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -378,7 +378,7 @@
                                              Member("s", ty.f16()),
                                          });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("ScalarPackedAtEndOfVec3"), type::AddressSpace::kUniform,
+    GlobalVar(Source{{78, 90}}, "a", ty("ScalarPackedAtEndOfVec3"), builtin::AddressSpace::kUniform,
               Group(0_a), Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -404,13 +404,13 @@
                   Member("scalar", ty.i32()),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.
+        R"(34:56 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
 12:34 note: see layout of struct:
 /*            align(4) size(44) */ struct Outer {
 /* offset( 0) align(4) size(40) */   inner : array<f32, 10>;
@@ -438,13 +438,13 @@
                   Member("scalar", ty.i32()),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 8. Consider using a vec4 instead.
+        R"(34:56 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'vec2<f32>' has a stride of 8 bytes. Consider using a vec4 instead.
 12:34 note: see layout of struct:
 /*            align(8) size(88) */ struct Outer {
 /* offset( 0) align(8) size(80) */   inner : array<vec2<f32>, 10>;
@@ -481,13 +481,13 @@
                   Member("scalar", ty.i32()),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 8. Consider using the @size attribute on the last struct member.
+        R"(34:56 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'ArrayElem' has a stride of 8 bytes. Consider using the @size attribute on the last struct member.
 12:34 note: see layout of struct:
 /*            align(4) size(84) */ struct Outer {
 /* offset( 0) align(4) size(80) */   inner : array<ArrayElem, 10>;
@@ -500,12 +500,12 @@
     // @group(0) @binding(0)
     // var<uniform> a : array<f32, 4u>;
     GlobalVar(Source{{78, 90}}, "a", ty.array(Source{{34, 56}}, ty.f32(), 4_u),
-              type::AddressSpace::kUniform, Group(0_a), Binding(0_a));
+              builtin::AddressSpace::kUniform, Group(0_a), Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(78:90 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.)");
+        R"(78:90 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.)");
 }
 
 TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_InvalidArrayStride_NestedArray) {
@@ -521,13 +521,13 @@
                   Member("inner", ty.array(Source{{34, 56}}, ty.array<f32, 4>(), 4_u)),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.
+        R"(34:56 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
 12:34 note: see layout of struct:
 /*            align(4) size(64) */ struct Outer {
 /* offset( 0) align(4) size(64) */   inner : array<array<f32, 4>, 4>;
@@ -554,7 +554,7 @@
                   Member("scalar", ty.i32()),
               });
 
-    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
+    GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
               Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -573,7 +573,7 @@
         Source{{12, 34}}, "S",
         utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
                       Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_i)})});
-    GlobalVar(Source{{78, 90}}, "a", ty("S"), type::AddressSpace::kPushConstant);
+    GlobalVar(Source{{78, 90}}, "a", ty("S"), builtin::AddressSpace::kPushConstant);
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -598,7 +598,7 @@
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
                                  Member("b", ty.f32(), utils::Vector{MemberAlign(4_i)})});
-    GlobalVar("a", ty("S"), type::AddressSpace::kPushConstant);
+    GlobalVar("a", ty("S"), builtin::AddressSpace::kPushConstant);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
diff --git a/src/tint/resolver/address_space_validation_test.cc b/src/tint/resolver/address_space_validation_test.cc
index 2c879de..a1b5ea8 100644
--- a/src/tint/resolver/address_space_validation_test.cc
+++ b/src/tint/resolver/address_space_validation_test.cc
@@ -32,8 +32,9 @@
     GlobalVar(Source{{12, 34}}, "g", ty.f32());
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: module-scope 'var' declaration must have a address space");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: module-scope 'var' declarations that are not of texture or sampler types must provide an address space)");
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_NoAddressSpace_Fail) {
@@ -46,7 +47,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_FunctionAddressSpace_Fail) {
     // var<private> g : f32;
-    GlobalVar(Source{{12, 34}}, "g", ty.f32(), type::AddressSpace::kFunction);
+    GlobalVar(Source{{12, 34}}, "g", ty.f32(), builtin::AddressSpace::kFunction);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -56,7 +57,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Private_RuntimeArray) {
     // var<private> v : array<i32>;
     GlobalVar(Source{{56, 78}}, "v", ty.array(Source{{12, 34}}, ty.i32()),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -67,7 +68,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Private_RuntimeArray) {
     // type t : ptr<private, array<i32>>;
     Alias("t", ty.pointer(Source{{56, 78}}, ty.array(Source{{12, 34}}, ty.i32()),
-                          type::AddressSpace::kPrivate));
+                          builtin::AddressSpace::kPrivate));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -79,7 +80,7 @@
     // struct S { m : array<i32> };
     // var<private> v : S;
     Structure("S", utils::Vector{Member(Source{{12, 34}}, "m", ty.array(ty.i32()))});
-    GlobalVar(Source{{56, 78}}, "v", ty("S"), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{56, 78}}, "v", ty("S"), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -92,7 +93,7 @@
     // struct S { m : array<i32> };
     // type t = ptr<private, S>;
     Structure("S", utils::Vector{Member(Source{{12, 34}}, "m", ty.array(ty.i32()))});
-    Alias("t", ty.pointer(ty("S"), type::AddressSpace::kPrivate));
+    Alias("t", ty.pointer(ty("S"), builtin::AddressSpace::kPrivate));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -104,7 +105,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Workgroup_RuntimeArray) {
     // var<workgroup> v : array<i32>;
     GlobalVar(Source{{56, 78}}, "v", ty.array(Source{{12, 34}}, ty.i32()),
-              type::AddressSpace::kWorkgroup);
+              builtin::AddressSpace::kWorkgroup);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -114,7 +115,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Workgroup_RuntimeArray) {
     // type t = ptr<workgroup, array<i32>>;
-    Alias("t", ty.pointer(ty.array(Source{{12, 34}}, ty.i32()), type::AddressSpace::kWorkgroup));
+    Alias("t", ty.pointer(ty.array(Source{{12, 34}}, ty.i32()), builtin::AddressSpace::kWorkgroup));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -126,7 +127,7 @@
     // struct S { m : array<i32> };
     // var<workgroup> v : S;
     Structure("S", utils::Vector{Member(Source{{12, 34}}, "m", ty.array(ty.i32()))});
-    GlobalVar(Source{{56, 78}}, "v", ty("S"), type::AddressSpace::kWorkgroup);
+    GlobalVar(Source{{56, 78}}, "v", ty("S"), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -139,7 +140,7 @@
     // struct S { m : array<i32> };
     // type t = ptr<workgroup, S>;
     Structure("S", utils::Vector{Member(Source{{12, 34}}, "m", ty.array(ty.i32()))});
-    Alias(Source{{56, 78}}, "t", ty.pointer(ty("S"), type::AddressSpace::kWorkgroup));
+    Alias(Source{{56, 78}}, "t", ty.pointer(ty("S"), builtin::AddressSpace::kWorkgroup));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -150,7 +151,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_Bool) {
     // var<storage> g : bool;
-    GlobalVar(Source{{56, 78}}, "g", ty.bool_(Source{{12, 34}}), type::AddressSpace::kStorage,
+    GlobalVar(Source{{56, 78}}, "g", ty.bool_(Source{{12, 34}}), builtin::AddressSpace::kStorage,
               Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -164,7 +165,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_Bool) {
     // type t = ptr<storage, bool>;
     Alias(Source{{56, 78}}, "t",
-          ty.pointer(ty.bool_(Source{{12, 34}}), type::AddressSpace::kStorage));
+          ty.pointer(ty.bool_(Source{{12, 34}}), builtin::AddressSpace::kStorage));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -178,7 +179,7 @@
     // type a = bool;
     // @binding(0) @group(0) var<storage, read> g : a;
     Alias("a", ty.bool_());
-    GlobalVar(Source{{56, 78}}, "g", ty(Source{{12, 34}}, "a"), type::AddressSpace::kStorage,
+    GlobalVar(Source{{56, 78}}, "g", ty(Source{{12, 34}}, "a"), builtin::AddressSpace::kStorage,
               Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -194,7 +195,7 @@
     // type t = ptr<storage, a>;
     Alias("a", ty.bool_());
     Alias(Source{{56, 78}}, "t",
-          ty.pointer(ty(Source{{12, 34}}, "a"), type::AddressSpace::kStorage));
+          ty.pointer(ty(Source{{12, 34}}, "a"), builtin::AddressSpace::kStorage));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -207,8 +208,8 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_Pointer) {
     // var<storage> g : ptr<private, f32>;
     GlobalVar(Source{{56, 78}}, "g",
-              ty.pointer(Source{{12, 34}}, ty.f32(), type::AddressSpace::kPrivate),
-              type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
+              ty.pointer(Source{{12, 34}}, ty.f32(), builtin::AddressSpace::kPrivate),
+              builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -221,8 +222,8 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_Pointer) {
     // type t = ptr<storage, ptr<private, f32>>;
     Alias("t", ty.pointer(Source{{56, 78}},
-                          ty.pointer(Source{{12, 34}}, ty.f32(), type::AddressSpace::kPrivate),
-                          type::AddressSpace::kStorage));
+                          ty.pointer(Source{{12, 34}}, ty.f32(), builtin::AddressSpace::kPrivate),
+                          builtin::AddressSpace::kStorage));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -234,14 +235,14 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_IntScalar) {
     // var<storage> g : i32;
-    GlobalVar("g", ty.i32(), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.i32(), builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_IntScalar) {
     // type t = ptr<storage, i32;
-    Alias("t", ty.pointer(ty.i32(), type::AddressSpace::kStorage));
+    Alias("t", ty.pointer(ty.i32(), builtin::AddressSpace::kStorage));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -251,7 +252,7 @@
     // var<storage> g : f16;
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("g", ty.f16(), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.f16(), builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -261,7 +262,7 @@
     // type t = ptr<storage, f16>;
     Enable(builtin::Extension::kF16);
 
-    Alias("t", ty.pointer(ty.f16(), type::AddressSpace::kStorage));
+    Alias("t", ty.pointer(ty.f16(), builtin::AddressSpace::kStorage));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -273,7 +274,7 @@
     Enable(builtin::Extension::kF16);
 
     Alias("a", ty.f16());
-    GlobalVar("g", ty("a"), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty("a"), builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -285,21 +286,21 @@
     Enable(builtin::Extension::kF16);
 
     Alias("a", ty.f16());
-    Alias("t", ty.pointer(ty("a"), type::AddressSpace::kStorage));
+    Alias("t", ty.pointer(ty("a"), builtin::AddressSpace::kStorage));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_VectorF32) {
     // var<storage> g : vec4<f32>;
-    GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_VectorF32) {
     // type t = ptr<storage, vec4<f32>>;
-    Alias("t", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kStorage));
+    Alias("t", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kStorage));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -307,7 +308,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_VectorF16) {
     // var<storage> g : vec4<f16>;
     Enable(builtin::Extension::kF16);
-    GlobalVar("g", ty.vec(ty.f16(), 4u), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.vec(ty.f16(), 4u), builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -315,7 +316,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_VectorF16) {
     // type t = ptr<storage, vec4<f16>>;
     Enable(builtin::Extension::kF16);
-    Alias("t", ty.pointer(ty.vec(ty.f16(), 4u), type::AddressSpace::kStorage));
+    Alias("t", ty.pointer(ty.vec(ty.f16(), 4u), builtin::AddressSpace::kStorage));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -324,7 +325,7 @@
     // struct S{ a : f32 };
     // var<storage, read> g : array<S, 3u>;
     Structure("S", utils::Vector{Member("a", ty.f32())});
-    GlobalVar("g", ty.array(ty("S"), 3_u), type::AddressSpace::kStorage, type::Access::kRead,
+    GlobalVar("g", ty.array(ty("S"), 3_u), builtin::AddressSpace::kStorage, builtin::Access::kRead,
               Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -334,7 +335,7 @@
     // struct S{ a : f32 };
     // type t = ptr<storage, array<S, 3u>>;
     Structure("S", utils::Vector{Member("a", ty.f32())});
-    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), type::AddressSpace::kStorage));
+    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), builtin::AddressSpace::kStorage));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -346,7 +347,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("a", ty.f16())});
-    GlobalVar("g", ty.array(ty("S"), 3_u), type::AddressSpace::kStorage, type::Access::kRead,
+    GlobalVar("g", ty.array(ty("S"), 3_u), builtin::AddressSpace::kStorage, builtin::Access::kRead,
               Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -359,8 +360,8 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("a", ty.f16())});
-    Alias("t",
-          ty.pointer(ty.array(ty("S"), 3_u), type::AddressSpace::kStorage, type::Access::kRead));
+    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), builtin::AddressSpace::kStorage,
+                          builtin::Access::kRead));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -369,7 +370,7 @@
     // struct S { x : i32 };
     // var<storage, read> g : S;
     Structure("S", utils::Vector{Member("x", ty.i32())});
-    GlobalVar("g", ty("S"), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
+    GlobalVar("g", ty("S"), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(0_a),
               Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -379,7 +380,7 @@
     // struct S { x : i32 };
     // type t = ptr<storage, read, S>;
     Structure("S", utils::Vector{Member("x", ty.i32())});
-    Alias("t", ty.pointer(ty("S"), type::AddressSpace::kStorage, type::Access::kRead));
+    Alias("t", ty.pointer(ty("S"), builtin::AddressSpace::kStorage, builtin::Access::kRead));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -391,7 +392,7 @@
     Structure("S", utils::Vector{Member("x", ty.i32())});
     Alias("a1", ty("S"));
     Alias("a2", ty("a1"));
-    GlobalVar("g", ty("a2"), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
+    GlobalVar("g", ty("a2"), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(0_a),
               Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -404,7 +405,7 @@
     Structure("S", utils::Vector{Member("x", ty.i32())});
     Alias("a1", ty("S"));
     Alias("a2", ty("a1"));
-    Alias("t", ty.pointer(ty("a2"), type::AddressSpace::kStorage, type::Access::kRead));
+    Alias("t", ty.pointer(ty("a2"), builtin::AddressSpace::kStorage, builtin::Access::kRead));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -415,7 +416,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
-    GlobalVar("g", ty("S"), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
+    GlobalVar("g", ty("S"), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(0_a),
               Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -427,7 +428,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
-    Alias("t", ty.pointer(ty("S"), type::AddressSpace::kStorage, type::Access::kRead));
+    Alias("t", ty.pointer(ty("S"), builtin::AddressSpace::kStorage, builtin::Access::kRead));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -441,7 +442,7 @@
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
     Alias("a2", ty("a1"));
-    GlobalVar("g", ty("a2"), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
+    GlobalVar("g", ty("a2"), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(0_a),
               Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -456,37 +457,38 @@
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
     Alias("a2", ty("a1"));
-    Alias("g", ty.pointer(ty("a2"), type::AddressSpace::kStorage, type::Access::kRead));
+    Alias("g", ty.pointer(ty("a2"), builtin::AddressSpace::kStorage, builtin::Access::kRead));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_NotStorage_AccessMode) {
     // var<private, read> g : a;
-    GlobalVar(Source{{12, 34}}, "g", ty.i32(), type::AddressSpace::kPrivate, type::Access::kRead);
+    GlobalVar(Source{{12, 34}}, "g", ty.i32(), builtin::AddressSpace::kPrivate,
+              builtin::Access::kRead);
 
     ASSERT_FALSE(r()->Resolve());
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: only variables in <storage> address space may declare an access mode)");
+        R"(12:34 error: only variables in <storage> address space may specify an access mode)");
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_NotStorage_AccessMode) {
     // type t = ptr<private, i32, read>;
-    Alias("t", ty.pointer(Source{{12, 34}}, ty.i32(), type::AddressSpace::kPrivate,
-                          type::Access::kRead));
+    Alias("t", ty.pointer(Source{{12, 34}}, ty.i32(), builtin::AddressSpace::kPrivate,
+                          builtin::Access::kRead));
 
     ASSERT_FALSE(r()->Resolve());
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: only pointers in <storage> address space may declare an access mode)");
+        R"(12:34 error: only pointers in <storage> address space may specify an access mode)");
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_ReadAccessMode) {
     // @group(0) @binding(0) var<storage, read> a : i32;
-    GlobalVar("a", ty.i32(), type::AddressSpace::kStorage, type::Access::kRead, Group(0_a),
+    GlobalVar("a", ty.i32(), builtin::AddressSpace::kStorage, builtin::Access::kRead, Group(0_a),
               Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -494,30 +496,30 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_ReadAccessMode) {
     // type t = ptr<storage, read, i32>;
-    Alias("t", ty.pointer(ty.i32(), type::AddressSpace::kStorage, type::Access::kRead));
+    Alias("t", ty.pointer(ty.i32(), builtin::AddressSpace::kStorage, builtin::Access::kRead));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_ReadWriteAccessMode) {
     // @group(0) @binding(0) var<storage, read_write> a : i32;
-    GlobalVar("a", ty.i32(), type::AddressSpace::kStorage, type::Access::kReadWrite, Group(0_a),
-              Binding(0_a));
+    GlobalVar("a", ty.i32(), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Group(0_a), Binding(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_ReadWriteAccessMode) {
     // type t = ptr<storage, read_write, i32>;
-    Alias("t", ty.pointer(ty.i32(), type::AddressSpace::kStorage, type::Access::kReadWrite));
+    Alias("t", ty.pointer(ty.i32(), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_WriteAccessMode) {
     // @group(0) @binding(0) var<storage, read_write> a : i32;
-    GlobalVar(Source{{12, 34}}, "a", ty.i32(), type::AddressSpace::kStorage, type::Access::kWrite,
-              Group(0_a), Binding(0_a));
+    GlobalVar(Source{{12, 34}}, "a", ty.i32(), builtin::AddressSpace::kStorage,
+              builtin::Access::kWrite, Group(0_a), Binding(0_a));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -527,8 +529,8 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_WriteAccessMode) {
     // type t = ptr<storage, read_write, i32>;
-    Alias("t", ty.pointer(Source{{12, 34}}, ty.i32(), type::AddressSpace::kStorage,
-                          type::Access::kWrite));
+    Alias("t", ty.pointer(Source{{12, 34}}, ty.i32(), builtin::AddressSpace::kStorage,
+                          builtin::Access::kWrite));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -543,7 +545,7 @@
     Structure("S",
               utils::Vector{Member(Source{{56, 78}}, "m", ty.array(Source{{12, 34}}, ty.i32()))});
 
-    GlobalVar(Source{{90, 12}}, "svar", ty("S"), type::AddressSpace::kUniform, Binding(0_a),
+    GlobalVar(Source{{90, 12}}, "svar", ty("S"), builtin::AddressSpace::kUniform, Binding(0_a),
               Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -560,12 +562,12 @@
     Structure("S",
               utils::Vector{Member(Source{{56, 78}}, "m", ty.array(Source{{12, 34}}, ty.i32()))});
 
-    Alias("t", ty.pointer(Source{{90, 12}}, ty("S"), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(Source{{90, 12}}, ty("S"), builtin::AddressSpace::kUniform));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.
+        R"(12:34 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'i32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
 note: see layout of struct:
 /*           align(4) size(4) */ struct S {
 /* offset(0) align(4) size(4) */   m : array<i32>;
@@ -575,7 +577,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferBool) {
     // var<uniform> g : bool;
-    GlobalVar(Source{{56, 78}}, "g", ty.bool_(Source{{12, 34}}), type::AddressSpace::kUniform,
+    GlobalVar(Source{{56, 78}}, "g", ty.bool_(Source{{12, 34}}), builtin::AddressSpace::kUniform,
               Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -588,8 +590,8 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferBool) {
     // type t = ptr<uniform, bool>;
-    Alias("t",
-          ty.pointer(Source{{56, 78}}, ty.bool_(Source{{12, 34}}), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(Source{{56, 78}}, ty.bool_(Source{{12, 34}}),
+                          builtin::AddressSpace::kUniform));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -603,7 +605,7 @@
     // type a = bool;
     // var<uniform> g : a;
     Alias("a", ty.bool_());
-    GlobalVar(Source{{56, 78}}, "g", ty(Source{{12, 34}}, "a"), type::AddressSpace::kUniform,
+    GlobalVar(Source{{56, 78}}, "g", ty(Source{{12, 34}}, "a"), builtin::AddressSpace::kUniform,
               Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -619,7 +621,7 @@
     // type t = ptr<uniform, a>;
     Alias("a", ty.bool_());
     Alias("t",
-          ty.pointer(Source{{56, 78}}, ty(Source{{12, 34}}, "a"), type::AddressSpace::kUniform));
+          ty.pointer(Source{{56, 78}}, ty(Source{{12, 34}}, "a"), builtin::AddressSpace::kUniform));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -632,8 +634,8 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformPointer) {
     // var<uniform> g : ptr<private, f32>;
     GlobalVar(Source{{56, 78}}, "g",
-              ty.pointer(Source{{12, 34}}, ty.f32(), type::AddressSpace::kPrivate),
-              type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+              ty.pointer(Source{{12, 34}}, ty.f32(), builtin::AddressSpace::kPrivate),
+              builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -646,8 +648,8 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformPointer) {
     // type t = ptr<uniform, ptr<private, f32>>;
     Alias("t", ty.pointer(Source{{56, 78}},
-                          ty.pointer(Source{{12, 34}}, ty.f32(), type::AddressSpace::kPrivate),
-                          type::AddressSpace::kUniform));
+                          ty.pointer(Source{{12, 34}}, ty.f32(), builtin::AddressSpace::kPrivate),
+                          builtin::AddressSpace::kUniform));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -659,7 +661,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferIntScalar) {
     // var<uniform> g : i32;
-    GlobalVar(Source{{56, 78}}, "g", ty.i32(), type::AddressSpace::kUniform, Binding(0_a),
+    GlobalVar(Source{{56, 78}}, "g", ty.i32(), builtin::AddressSpace::kUniform, Binding(0_a),
               Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -667,7 +669,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferIntScalar) {
     // type t = ptr<uniform, i32>;
-    Alias("t", ty.pointer(ty.i32(), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty.i32(), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -677,7 +679,7 @@
     // var<uniform> g : f16;
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("g", ty.f16(), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.f16(), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -687,21 +689,21 @@
     // type t = ptr<uniform, f16>;
     Enable(builtin::Extension::kF16);
 
-    Alias("t", ty.pointer(ty.f16(), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty.f16(), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferVectorF32) {
     // var<uniform> g : vec4<f32>;
-    GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferVectorF32) {
     // type t = ptr<uniform, vec4<f32>>;
-    Alias("t", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -711,7 +713,7 @@
     // var<uniform> g : vec4<f16>;
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -721,7 +723,7 @@
     // type t = ptr<uniform, vec4<f16>>;
     Enable(builtin::Extension::kF16);
 
-    Alias("t", ty.pointer(ty.vec4<f16>(), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty.vec4<f16>(), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -732,7 +734,8 @@
     // }
     // var<uniform> g : array<S, 3u>;
     Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(16_a)})});
-    GlobalVar("g", ty.array(ty("S"), 3_u), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.array(ty("S"), 3_u), builtin::AddressSpace::kUniform, Binding(0_a),
+              Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -743,7 +746,7 @@
     // }
     // type t = ptr<uniform, array<S, 3u>>;
     Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(16_a)})});
-    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -757,7 +760,8 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("a", ty.f16(), utils::Vector{MemberSize(16_a)})});
-    GlobalVar("g", ty.array(ty("S"), 3_u), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty.array(ty("S"), 3_u), builtin::AddressSpace::kUniform, Binding(0_a),
+              Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -771,7 +775,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("a", ty.f16(), utils::Vector{MemberSize(16_a)})});
-    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -780,7 +784,7 @@
     // struct S { x : i32 };
     // var<uniform> g : S;
     Structure("S", utils::Vector{Member("x", ty.i32())});
-    GlobalVar("g", ty("S"), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty("S"), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -789,7 +793,7 @@
     // struct S { x : i32 };
     // type t = ptr<uniform, S>;
     Structure("S", utils::Vector{Member("x", ty.i32())});
-    Alias("t", ty.pointer(ty("S"), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty("S"), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -800,7 +804,7 @@
     // var<uniform> g : a1;
     Structure("S", utils::Vector{Member("x", ty.i32())});
     Alias("a1", ty("S"));
-    GlobalVar("g", ty("a1"), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty("a1"), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -811,7 +815,7 @@
     // type t = ptr<uniform, a1>;
     Structure("S", utils::Vector{Member("x", ty.i32())});
     Alias("a1", ty("S"));
-    Alias("t", ty.pointer(ty("a1"), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty("a1"), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -823,7 +827,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
-    GlobalVar("g", ty("S"), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty("S"), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -835,7 +839,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
-    Alias("t", ty.pointer(ty("S"), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty("S"), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -849,7 +853,7 @@
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
-    GlobalVar("g", ty("a1"), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("g", ty("a1"), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -863,7 +867,7 @@
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
-    Alias("t", ty.pointer(ty("a1"), type::AddressSpace::kUniform));
+    Alias("t", ty.pointer(ty("a1"), builtin::AddressSpace::kUniform));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -872,7 +876,8 @@
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : bool;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar(Source{{56, 78}}, "g", ty.bool_(Source{{12, 34}}), type::AddressSpace::kPushConstant);
+    GlobalVar(Source{{56, 78}}, "g", ty.bool_(Source{{12, 34}}),
+              builtin::AddressSpace::kPushConstant);
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -886,7 +891,7 @@
     // type t = ptr<push_constant, bool>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Alias(Source{{56, 78}}, "t",
-          ty.pointer(ty.bool_(Source{{12, 34}}), type::AddressSpace::kPushConstant));
+          ty.pointer(ty.bool_(Source{{12, 34}}), builtin::AddressSpace::kPushConstant));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -901,7 +906,7 @@
     // var<push_constant> g : f16;
     Enable(builtin::Extension::kF16);
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar("g", ty.f16(Source{{56, 78}}), type::AddressSpace::kPushConstant);
+    GlobalVar("g", ty.f16(Source{{56, 78}}), builtin::AddressSpace::kPushConstant);
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -914,7 +919,7 @@
     // type t = ptr<push_constant, f16>;
     Enable(builtin::Extension::kF16);
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    Alias("t", ty.pointer(ty.f16(Source{{56, 78}}), type::AddressSpace::kPushConstant));
+    Alias("t", ty.pointer(ty.f16(Source{{56, 78}}), builtin::AddressSpace::kPushConstant));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -926,8 +931,8 @@
     // var<push_constant> g : ptr<private, f32>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar(Source{{56, 78}}, "g",
-              ty.pointer(Source{{12, 34}}, ty.f32(), type::AddressSpace::kPrivate),
-              type::AddressSpace::kPushConstant);
+              ty.pointer(Source{{12, 34}}, ty.f32(), builtin::AddressSpace::kPrivate),
+              builtin::AddressSpace::kPushConstant);
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -941,8 +946,8 @@
     // type t = ptr<push_constant, ptr<private, f32>>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Alias(Source{{56, 78}}, "t",
-          ty.pointer(ty.pointer(Source{{12, 34}}, ty.f32(), type::AddressSpace::kPrivate),
-                     type::AddressSpace::kPushConstant));
+          ty.pointer(ty.pointer(Source{{12, 34}}, ty.f32(), builtin::AddressSpace::kPrivate),
+                     builtin::AddressSpace::kPushConstant));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -955,7 +960,7 @@
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : i32;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar("g", ty.i32(), type::AddressSpace::kPushConstant);
+    GlobalVar("g", ty.i32(), builtin::AddressSpace::kPushConstant);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -964,7 +969,7 @@
     // enable chromium_experimental_push_constant;
     // type t = ptr<push_constant, i32>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    Alias("t", ty.pointer(ty.i32(), type::AddressSpace::kPushConstant));
+    Alias("t", ty.pointer(ty.i32(), builtin::AddressSpace::kPushConstant));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -973,7 +978,7 @@
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : vec4<f32>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPushConstant);
+    GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPushConstant);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -982,7 +987,7 @@
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : vec4<f32>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    Alias("t", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kPushConstant));
+    Alias("t", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kPushConstant));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -993,7 +998,7 @@
     // var<push_constant> g : array<S, 3u>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Structure("S", utils::Vector{Member("a", ty.f32())});
-    GlobalVar("g", ty.array(ty("S"), 3_u), type::AddressSpace::kPushConstant);
+    GlobalVar("g", ty.array(ty("S"), 3_u), builtin::AddressSpace::kPushConstant);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -1004,7 +1009,7 @@
     // type t = ptr<push_constant, array<S, 3u>>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Structure("S", utils::Vector{Member("a", ty.f32())});
-    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), type::AddressSpace::kPushConstant));
+    Alias("t", ty.pointer(ty.array(ty("S"), 3_u), builtin::AddressSpace::kPushConstant));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
diff --git a/src/tint/resolver/alias_analysis_test.cc b/src/tint/resolver/alias_analysis_test.cc
index cc55f0b..fa70a7f 100644
--- a/src/tint/resolver/alias_analysis_test.cc
+++ b/src/tint/resolver/alias_analysis_test.cc
@@ -35,19 +35,19 @@
 //   target(&v1, aliased ? &v1 : &v2);
 // }
 struct TwoPointerConfig {
-    type::AddressSpace address_space;  // The address space for the pointers.
-    bool aliased;                      // Whether the pointers alias or not.
+    builtin::AddressSpace address_space;  // The address space for the pointers.
+    bool aliased;                         // Whether the pointers alias or not.
 };
 class TwoPointers : public ResolverTestWithParam<TwoPointerConfig> {
   protected:
     void SetUp() override {
         utils::Vector<const ast::Statement*, 4> body;
-        if (GetParam().address_space == type::AddressSpace::kFunction) {
+        if (GetParam().address_space == builtin::AddressSpace::kFunction) {
             body.Push(Decl(Var("v1", ty.i32())));
             body.Push(Decl(Var("v2", ty.i32())));
         } else {
-            GlobalVar("v1", type::AddressSpace::kPrivate, ty.i32());
-            GlobalVar("v2", type::AddressSpace::kPrivate, ty.i32());
+            GlobalVar("v1", builtin::AddressSpace::kPrivate, ty.i32());
+            GlobalVar("v2", builtin::AddressSpace::kPrivate, ty.i32());
         }
         body.Push(CallStmt(Call("target", AddressOf(Source{{12, 34}}, "v1"),
                                 AddressOf(Source{{56, 78}}, GetParam().aliased ? "v1" : "v2"))));
@@ -190,10 +190,11 @@
 
 INSTANTIATE_TEST_SUITE_P(ResolverAliasAnalysisTest,
                          TwoPointers,
-                         ::testing::Values(TwoPointerConfig{type::AddressSpace::kFunction, false},
-                                           TwoPointerConfig{type::AddressSpace::kFunction, true},
-                                           TwoPointerConfig{type::AddressSpace::kPrivate, false},
-                                           TwoPointerConfig{type::AddressSpace::kPrivate, true}),
+                         ::testing::Values(TwoPointerConfig{builtin::AddressSpace::kFunction,
+                                                            false},
+                                           TwoPointerConfig{builtin::AddressSpace::kFunction, true},
+                                           TwoPointerConfig{builtin::AddressSpace::kPrivate, false},
+                                           TwoPointerConfig{builtin::AddressSpace::kPrivate, true}),
                          [](const ::testing::TestParamInfo<TwoPointers::ParamType>& p) {
                              std::stringstream ss;
                              ss << (p.param.aliased ? "Aliased" : "Unaliased") << "_"
@@ -214,8 +215,8 @@
 class OnePointerOneModuleScope : public ResolverTestWithParam<bool> {
   protected:
     void SetUp() override {
-        GlobalVar("global_1", type::AddressSpace::kPrivate, ty.i32());
-        GlobalVar("global_2", type::AddressSpace::kPrivate, ty.i32());
+        GlobalVar("global_1", builtin::AddressSpace::kPrivate, ty.i32());
+        GlobalVar("global_2", builtin::AddressSpace::kPrivate, ty.i32());
         Func("caller", utils::Empty, ty.void_(),
              utils::Vector{
                  CallStmt(Call("target",
@@ -226,7 +227,7 @@
     void Run(utils::Vector<const ast::Statement*, 4>&& body, const char* err = nullptr) {
         Func("target",
              utils::Vector<const ast::Parameter*, 4>{
-                 Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+                 Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
              },
              ty.void_(), std::move(body));
         if (GetParam() && err) {
@@ -295,7 +296,7 @@
     // f1(p1);
     Func("f2",
          utils::Vector<const ast::Parameter*, 4>{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -303,7 +304,7 @@
          });
     Func("f1",
          utils::Vector<const ast::Parameter*, 4>{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -330,7 +331,7 @@
     // f1(p1);
     Func("f2",
          utils::Vector<const ast::Parameter*, 4>{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -339,7 +340,7 @@
          });
     Func("f1",
          utils::Vector<const ast::Parameter*, 4>{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -365,7 +366,7 @@
     // f1(p1);
     Func("f2",
          utils::Vector<const ast::Parameter*, 4>{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -373,7 +374,7 @@
          });
     Func("f1",
          utils::Vector<const ast::Parameter*, 4>{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -400,7 +401,7 @@
     // f1(p1);
     Func("f2",
          utils::Vector{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -409,7 +410,7 @@
          });
     Func("f1",
          utils::Vector{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -435,7 +436,7 @@
     // f2();
     Func("f1",
          utils::Vector{
-             Param("p1", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p1", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(),
          utils::Vector{
@@ -487,8 +488,8 @@
     void Run(const ast::Statement* stmt, const char* err = nullptr) {
         Func("target",
              utils::Vector{
-                 Param("p1", ty.pointer<i32>(type::AddressSpace::kFunction)),
-                 Param("p2", ty.pointer<i32>(type::AddressSpace::kFunction)),
+                 Param("p1", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
+                 Param("p2", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
              },
              ty.void_(),
              utils::Vector{
@@ -531,7 +532,7 @@
 TEST_P(Use, Read_CompoundAssignment_RHS) {
     // var<private> global : i32;
     // global += *p2;
-    GlobalVar("global", type::AddressSpace::kPrivate, ty.i32());
+    GlobalVar("global", builtin::AddressSpace::kPrivate, ty.i32());
     Run(CompoundAssign("global", Deref("p2"), ast::BinaryOp::kAdd),
         R"(56:78 error: invalid aliased pointer argument
 12:34 note: aliases with another argument passed here)");
@@ -557,7 +558,7 @@
 
 TEST_P(Use, Read_FunctionCallArg) {
     // abs(*p2);
-    Run(CallStmt(Call("abs", Deref("p2"))), R"(56:78 error: invalid aliased pointer argument
+    Run(Assign(Phony(), Call("abs", Deref("p2"))), R"(56:78 error: invalid aliased pointer argument
 12:34 note: aliases with another argument passed here)");
 }
 
@@ -578,7 +579,7 @@
 TEST_P(Use, Read_IndexAccessor) {
     // var<private> data : array<f32, 4>;
     // _ = data[*p2];
-    GlobalVar("data", type::AddressSpace::kPrivate, ty.array<f32, 4>());
+    GlobalVar("data", builtin::AddressSpace::kPrivate, ty.array<f32, 4>());
     Run(Assign(Phony(), IndexAccessor("data", Deref("p2"))),
         R"(56:78 error: invalid aliased pointer argument
 12:34 note: aliases with another argument passed here)");
@@ -592,7 +593,7 @@
 
 TEST_P(Use, Read_VarInitializer) {
     // var x = *p2;
-    Run(Decl(Var("x", type::AddressSpace::kFunction, Deref("p2"))),
+    Run(Decl(Var("x", builtin::AddressSpace::kFunction, Deref("p2"))),
         R"(56:78 error: invalid aliased pointer argument
 12:34 note: aliases with another argument passed here)");
 }
@@ -602,7 +603,7 @@
     // foo(p2);
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.i32(),
          utils::Vector{
@@ -659,8 +660,8 @@
     void Run(const ast::Statement* stmt, const char* err = nullptr) {
         Func("target",
              utils::Vector{
-                 Param("p1", ty.pointer<bool>(type::AddressSpace::kFunction)),
-                 Param("p2", ty.pointer<bool>(type::AddressSpace::kFunction)),
+                 Param("p1", ty.pointer<bool>(builtin::AddressSpace::kFunction)),
+                 Param("p2", ty.pointer<bool>(builtin::AddressSpace::kFunction)),
              },
              ty.void_(),
              utils::Vector{
@@ -724,8 +725,8 @@
     Structure("S", utils::Vector{Member("a", ty.i32())});
     Func("f2",
          utils::Vector{
-             Param("p1", ty.pointer(ty("S"), type::AddressSpace::kFunction)),
-             Param("p2", ty.pointer(ty("S"), type::AddressSpace::kFunction)),
+             Param("p1", ty.pointer(ty("S"), builtin::AddressSpace::kFunction)),
+             Param("p2", ty.pointer(ty("S"), builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
@@ -753,8 +754,8 @@
     Structure("S", utils::Vector{Member("a", ty.i32())});
     Func("f2",
          utils::Vector{
-             Param("p1", ty.pointer(ty("S"), type::AddressSpace::kFunction)),
-             Param("p2", ty.pointer(ty("S"), type::AddressSpace::kFunction)),
+             Param("p1", ty.pointer(ty("S"), builtin::AddressSpace::kFunction)),
+             Param("p2", ty.pointer(ty("S"), builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
@@ -785,8 +786,8 @@
     Structure("S", utils::Vector{Member("a", ty.i32())});
     Func("f2",
          utils::Vector{
-             Param("p1", ty.pointer(ty("S"), type::AddressSpace::kFunction)),
-             Param("p2", ty.pointer(ty("S"), type::AddressSpace::kFunction)),
+             Param("p1", ty.pointer(ty("S"), builtin::AddressSpace::kFunction)),
+             Param("p2", ty.pointer(ty("S"), builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
@@ -816,8 +817,8 @@
     Structure("S", utils::Vector{Member("a", ty.i32())});
     Func("f2",
          utils::Vector{
-             Param("p1", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kFunction)),
-             Param("p2", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kFunction)),
+             Param("p1", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kFunction)),
+             Param("p2", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
@@ -848,7 +849,7 @@
     // }
     Func("f1",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
@@ -901,7 +902,7 @@
     // }
     Func("f2",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
@@ -909,7 +910,7 @@
          });
     Func("f3",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
diff --git a/src/tint/resolver/array_accessor_test.cc b/src/tint/resolver/array_accessor_test.cc
index fc7bdeb..e18a618 100644
--- a/src/tint/resolver/array_accessor_test.cc
+++ b/src/tint/resolver/array_accessor_test.cc
@@ -27,7 +27,7 @@
 using ResolverIndexAccessorTest = ResolverTest;
 
 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_F32) {
-    GlobalVar("my_var", ty.mat2x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.mat2x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1_f));
     WrapInFunction(acc);
 
@@ -36,7 +36,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_Ref) {
-    GlobalVar("my_var", ty.mat2x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.mat2x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* idx = Var("idx", ty.i32(), Call<i32>());
     auto* acc = IndexAccessor("my_var", idx);
     WrapInFunction(Decl(idx), acc);
@@ -50,7 +50,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions_Dynamic_Ref) {
-    GlobalVar("my_var", ty.mat4x4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.mat4x4<f32>(), builtin::AddressSpace::kPrivate);
     auto* idx = Var("idx", ty.u32(), Expr(3_u));
     auto* idy = Var("idy", ty.u32(), Expr(2_u));
     auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy);
@@ -100,7 +100,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix) {
-    GlobalVar("my_var", ty.mat2x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.mat2x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* acc = IndexAccessor("my_var", 1_i);
     WrapInFunction(acc);
@@ -118,7 +118,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions) {
-    GlobalVar("my_var", ty.mat2x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.mat2x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* acc = IndexAccessor(IndexAccessor("my_var", 0_i), 1_i);
     WrapInFunction(acc);
@@ -135,7 +135,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Vector_F32) {
-    GlobalVar("my_var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
     auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2_f));
     WrapInFunction(acc);
 
@@ -144,7 +144,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Vector_Dynamic_Ref) {
-    GlobalVar("my_var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
     auto* idx = Var("idx", ty.i32(), Expr(2_i));
     auto* acc = IndexAccessor("my_var", idx);
     WrapInFunction(Decl(idx), acc);
@@ -167,7 +167,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Vector) {
-    GlobalVar("my_var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* acc = IndexAccessor("my_var", 2_i);
     WrapInFunction(acc);
@@ -184,7 +184,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Array_Literal_i32) {
-    GlobalVar("my_var", ty.array<f32, 3>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.array<f32, 3>(), builtin::AddressSpace::kPrivate);
     auto* acc = IndexAccessor("my_var", 2_i);
     WrapInFunction(acc);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -197,7 +197,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Array_Literal_u32) {
-    GlobalVar("my_var", ty.array<f32, 3>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.array<f32, 3>(), builtin::AddressSpace::kPrivate);
     auto* acc = IndexAccessor("my_var", 2_u);
     WrapInFunction(acc);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -210,7 +210,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Array_Literal_AInt) {
-    GlobalVar("my_var", ty.array<f32, 3>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.array<f32, 3>(), builtin::AddressSpace::kPrivate);
     auto* acc = IndexAccessor("my_var", 2_a);
     WrapInFunction(acc);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -225,7 +225,7 @@
 TEST_F(ResolverIndexAccessorTest, Alias_Array) {
     auto* aary = Alias("myarrty", ty.array<f32, 3>());
 
-    GlobalVar("my_var", ty.Of(aary), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.Of(aary), builtin::AddressSpace::kPrivate);
 
     auto* acc = IndexAccessor("my_var", 2_i);
     WrapInFunction(acc);
@@ -316,7 +316,7 @@
     //     let x: f32 = (*p)[idx];
     //     return x;
     // }
-    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kFunction));
+    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kFunction));
     auto* idx = Let("idx", ty.u32(), Call<u32>());
     auto* star_p = Deref(p);
     auto* acc = IndexAccessor(Source{{12, 34}}, star_p, idx);
@@ -337,7 +337,7 @@
     //     let x: f32 = *p[idx];
     //     return x;
     // }
-    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kFunction));
+    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kFunction));
     auto* idx = Let("idx", ty.u32(), Call<u32>());
     auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
     auto* star_p = Deref(accessor_expr);
diff --git a/src/tint/resolver/assignment_validation_test.cc b/src/tint/resolver/assignment_validation_test.cc
index cf8b505..1c57463 100644
--- a/src/tint/resolver/assignment_validation_test.cc
+++ b/src/tint/resolver/assignment_validation_test.cc
@@ -33,8 +33,8 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("m", ty.i32()),
                              });
-    GlobalVar(Source{{12, 34}}, "a", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-              Binding(0_a), Group(0_a));
+    GlobalVar(Source{{12, 34}}, "a", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Binding(0_a), Group(0_a));
 
     WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("a", "m"), 1_i));
 
@@ -143,17 +143,6 @@
     EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
 }
 
-TEST_F(ResolverAssignmentValidationTest, AssignToScalar_Fail) {
-    // var my_var : i32 = 2i;
-    // 1 = my_var;
-
-    WrapInFunction(Var("my_var", ty.i32(), Expr(2_i)),  //
-                   Assign(Expr(Source{{12, 34}}, 1_i), "my_var"));
-
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: cannot assign to value of type 'i32'");
-}
-
 TEST_F(ResolverAssignmentValidationTest, AssignCompatibleTypes_Pass) {
     // var a : i32 = 1i;
     // a = 2i;
@@ -193,7 +182,7 @@
     // var a : i32;
     // let b : ptr<function,i32> = &a;
     // *b = 2i;
-    const auto func = type::AddressSpace::kFunction;
+    const auto func = builtin::AddressSpace::kFunction;
     WrapInFunction(Var("a", ty.i32(), func, Expr(2_i)),                    //
                    Let("b", ty.pointer<i32>(func), AddressOf(Expr("a"))),  //
                    Assign(Deref("b"), 2_i));
@@ -205,7 +194,7 @@
     // var a : i32;
     // let b : ptr<function,i32> = &a;
     // *b = 2;
-    const auto func = type::AddressSpace::kFunction;
+    const auto func = builtin::AddressSpace::kFunction;
     auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
     auto* var_b = Let("b", ty.pointer<i32>(func), AddressOf(Expr("a")));
     WrapInFunction(var_a, var_b, Assign(Deref("b"), 2_a));
@@ -213,16 +202,87 @@
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
+TEST_F(ResolverAssignmentValidationTest, AssignToScalar_Fail) {
+    // var my_var : i32 = 2i;
+    // 1 = my_var;
+
+    WrapInFunction(Var("my_var", ty.i32(), Expr(2_i)),  //
+                   Assign(Expr(Source{{12, 34}}, 1_i), "my_var"));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to value expression of type 'i32')");
+}
+
+TEST_F(ResolverAssignmentValidationTest, AssignToOverride_Fail) {
+    // override a : i32 = 2i;
+    // {
+    //  a = 2i
+    // }
+    Override(Source{{56, 78}}, "a", ty.i32(), Expr(2_i));
+    WrapInFunction(Assign(Expr(Source{{12, 34}}, "a"), 2_i));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to override 'a'
+12:34 note: 'override' variables are immutable
+56:78 note: override 'a' declared here)");
+}
+
 TEST_F(ResolverAssignmentValidationTest, AssignToLet_Fail) {
     // {
     //  let a : i32 = 2i;
     //  a = 2i
     // }
-    auto* var = Let("a", ty.i32(), Expr(2_i));
-    WrapInFunction(var, Assign(Expr(Source{{12, 34}}, "a"), 2_i));
+    WrapInFunction(Let(Source{{56, 78}}, "a", ty.i32(), Expr(2_i)),  //
+                   Assign(Expr(Source{{12, 34}}, "a"), 2_i));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: cannot assign to 'let'\nnote: 'a' is declared here:");
+    EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to let 'a'
+12:34 note: 'let' variables are immutable
+56:78 note: let 'a' declared here)");
+}
+
+TEST_F(ResolverAssignmentValidationTest, AssignToConst_Fail) {
+    // {
+    //  const a : i32 = 2i;
+    //  a = 2i
+    // }
+    WrapInFunction(Const(Source{{56, 78}}, "a", ty.i32(), Expr(2_i)),  //
+                   Assign(Expr(Source{{12, 34}}, "a"), 2_i));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to const 'a'
+12:34 note: 'const' variables are immutable
+56:78 note: const 'a' declared here)");
+}
+
+TEST_F(ResolverAssignmentValidationTest, AssignToParam_Fail) {
+    Func("foo", utils::Vector{Param(Source{{56, 78}}, "arg", ty.i32())}, ty.void_(),
+         utils::Vector{
+             Assign(Expr(Source{{12, 34}}, "arg"), Expr(1_i)),
+             Return(),
+         });
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: cannot assign to parameter 'arg'
+12:34 note: parameters are immutable
+56:78 note: parameter 'arg' declared here)");
+}
+
+TEST_F(ResolverAssignmentValidationTest, AssignToLetMember_Fail) {
+    // struct S { i : i32 }
+    // {
+    //  let a : S;
+    //  a.i = 2i
+    // }
+    Structure("S", utils::Vector{Member("i", ty.i32())});
+    WrapInFunction(Let(Source{{98, 76}}, "a", ty("S"), Call("S")),  //
+                   Assign(MemberAccessor(Source{{12, 34}}, Expr(Source{{56, 78}}, "a"), "i"), 2_i));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to value expression of type 'i32'
+56:78 note: 'let' variables are immutable
+98:76 note: let 'a' declared here)");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Handle) {
@@ -231,8 +291,8 @@
     // a = b;
 
     auto make_type = [&] {
-        return ty.storage_texture(type::TextureDimension::k1d, type::TexelFormat::kRgba8Unorm,
-                                  type::Access::kWrite);
+        return ty.storage_texture(type::TextureDimension::k1d, builtin::TexelFormat::kRgba8Unorm,
+                                  builtin::Access::kWrite);
     };
 
     GlobalVar("a", make_type(), Binding(0_a), Group(0_a));
@@ -252,8 +312,8 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("a", ty.atomic(ty.i32())),
                              });
-    GlobalVar(Source{{12, 34}}, "v", ty.Of(s), type::AddressSpace::kStorage,
-              type::Access::kReadWrite, Binding(0_a), Group(0_a));
+    GlobalVar(Source{{12, 34}}, "v", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kReadWrite, Binding(0_a), Group(0_a));
 
     WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
 
@@ -269,8 +329,8 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("a", ty.array(ty.f32())),
                              });
-    GlobalVar(Source{{12, 34}}, "v", ty.Of(s), type::AddressSpace::kStorage,
-              type::Access::kReadWrite, Binding(0_a), Group(0_a));
+    GlobalVar(Source{{12, 34}}, "v", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kReadWrite, Binding(0_a), Group(0_a));
 
     WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
 
@@ -289,7 +349,7 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("arr", ty.array<i32>()),
                              });
-    GlobalVar("s", ty.Of(s), type::AddressSpace::kStorage, Group(0_a), Binding(0_a));
+    GlobalVar("s", ty.Of(s), builtin::AddressSpace::kStorage, Group(0_a), Binding(0_a));
 
     WrapInFunction(Assign(Phony(), Expr(Source{{12, 34}}, "s")));
 
@@ -311,7 +371,7 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("arr", ty.array<i32>()),
                              });
-    GlobalVar("s", ty.Of(s), type::AddressSpace::kStorage, Group(0_a), Binding(0_a));
+    GlobalVar("s", ty.Of(s), builtin::AddressSpace::kStorage, Group(0_a), Binding(0_a));
 
     WrapInFunction(Assign(Phony(), MemberAccessor(Source{{12, 34}}, "s", "arr")));
 
@@ -364,9 +424,9 @@
     GlobalVar("tex", ty.sampled_texture(type::TextureDimension::k2d, ty.f32()), Group(0_a),
               Binding(0_a));
     GlobalVar("smp", ty.sampler(type::SamplerKind::kSampler), Group(0_a), Binding(1_a));
-    GlobalVar("u", ty.Of(U), type::AddressSpace::kUniform, Group(0_a), Binding(2_a));
-    GlobalVar("s", ty.Of(S), type::AddressSpace::kStorage, Group(0_a), Binding(3_a));
-    GlobalVar("wg", ty.array<f32, 10>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("u", ty.Of(U), builtin::AddressSpace::kUniform, Group(0_a), Binding(2_a));
+    GlobalVar("s", ty.Of(S), builtin::AddressSpace::kStorage, Group(0_a), Binding(3_a));
+    GlobalVar("wg", ty.array<f32, 10>(), builtin::AddressSpace::kWorkgroup);
 
     WrapInFunction(Assign(Phony(), 1_i),                                    //
                    Assign(Phony(), 2_u),                                    //
diff --git a/src/tint/resolver/atomics_test.cc b/src/tint/resolver/atomics_test.cc
index ba83fcd..f079159 100644
--- a/src/tint/resolver/atomics_test.cc
+++ b/src/tint/resolver/atomics_test.cc
@@ -27,7 +27,8 @@
 struct ResolverAtomicTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverAtomicTest, GlobalWorkgroupI32) {
-    auto* g = GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), type::AddressSpace::kWorkgroup);
+    auto* g =
+        GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
     ASSERT_TRUE(TypeOf(g)->Is<type::Reference>());
@@ -37,7 +38,8 @@
 }
 
 TEST_F(ResolverAtomicTest, GlobalWorkgroupU32) {
-    auto* g = GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.u32()), type::AddressSpace::kWorkgroup);
+    auto* g =
+        GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.u32()), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
     ASSERT_TRUE(TypeOf(g)->Is<type::Reference>());
@@ -48,7 +50,7 @@
 
 TEST_F(ResolverAtomicTest, GlobalStorageStruct) {
     auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
-    auto* g = GlobalVar("g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    auto* g = GlobalVar("g", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                         Binding(0_a), Group(0_a));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/atomics_validation_test.cc b/src/tint/resolver/atomics_validation_test.cc
index bd0c5cc..a557956 100644
--- a/src/tint/resolver/atomics_validation_test.cc
+++ b/src/tint/resolver/atomics_validation_test.cc
@@ -27,35 +27,35 @@
 struct ResolverAtomicValidationTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverAtomicValidationTest, AddressSpace_WorkGroup) {
-    GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverAtomicValidationTest, AddressSpace_Storage) {
-    GlobalVar("g", ty.atomic(Source{{12, 34}}, ty.i32()), type::AddressSpace::kStorage,
-              type::Access::kReadWrite, Group(0_a), Binding(0_a));
+    GlobalVar("g", ty.atomic(Source{{12, 34}}, ty.i32()), builtin::AddressSpace::kStorage,
+              builtin::Access::kReadWrite, Group(0_a), Binding(0_a));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAtomicValidationTest, AddressSpace_Storage_Struct) {
     auto* s = Structure("s", utils::Vector{Member(Source{{12, 34}}, "a", ty.atomic(ty.i32()))});
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Group(0_a),
-              Binding(0_a));
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Group(0_a), Binding(0_a));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidType) {
-    GlobalVar("a", ty.atomic(ty.f32(Source{{12, 34}})), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic(ty.f32(Source{{12, 34}})), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: atomic only supports i32 or u32 types");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Simple) {
-    GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -63,7 +63,7 @@
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Array) {
-    GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -72,7 +72,7 @@
 
 TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Struct) {
     auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(ty.i32()))});
-    GlobalVar(Source{{56, 78}}, "g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{56, 78}}, "g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -88,7 +88,7 @@
     auto* Inner =
         Structure("Inner", utils::Vector{Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
     auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
-    GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -104,7 +104,7 @@
     auto* Inner =
         Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
     auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
-    GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -118,7 +118,7 @@
 
     auto* atomic_array =
         Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
-    GlobalVar(Source{{56, 78}}, "v", ty.Of(atomic_array), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{56, 78}}, "v", ty.Of(atomic_array), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -132,7 +132,7 @@
     // var<private> v: array<S, 5u>;
 
     auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic<u32>())});
-    GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -149,7 +149,7 @@
 
     auto* atomic_array = Alias("AtomicArray", ty.atomic(ty.i32()));
     auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "m", ty.Of(atomic_array))});
-    GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -188,7 +188,7 @@
     auto* s2 = Structure("S2", utils::Vector{Member("x", ty.Of(s3))});
     auto* s1 = Structure("S1", utils::Vector{Member("x", ty.Of(s2))});
     auto* s0 = Structure("S0", utils::Vector{Member("x", ty.Of(s1))});
-    GlobalVar(Source{{56, 78}}, "g", ty.Of(s0), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{56, 78}}, "g", ty.Of(s0), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -198,8 +198,8 @@
 
 TEST_F(ResolverAtomicValidationTest, Struct_AccessMode_Read) {
     auto* s = Structure("s", utils::Vector{Member(Source{{12, 34}}, "a", ty.atomic(ty.i32()))});
-    GlobalVar(Source{{56, 78}}, "g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-              Group(0_a), Binding(0_a));
+    GlobalVar(Source{{56, 78}}, "g", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Group(0_a), Binding(0_a));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -210,8 +210,8 @@
 
 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Struct) {
     auto* s = Structure("s", utils::Vector{Member(Source{{12, 34}}, "a", ty.atomic(ty.i32()))});
-    GlobalVar(Source{{56, 78}}, "g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-              Group(0_a), Binding(0_a));
+    GlobalVar(Source{{56, 78}}, "g", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Group(0_a), Binding(0_a));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -228,8 +228,8 @@
     auto* Inner =
         Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
     auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
-    GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), type::AddressSpace::kStorage,
-              type::Access::kRead, Group(0_a), Binding(0_a));
+    GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Group(0_a), Binding(0_a));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -246,8 +246,8 @@
     auto* Inner =
         Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
     auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
-    GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), type::AddressSpace::kStorage,
-              type::Access::kRead, Group(0_a), Binding(0_a));
+    GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Group(0_a), Binding(0_a));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -287,8 +287,8 @@
     auto* s2 = Structure("S2", utils::Vector{Member("x", ty.Of(s3))});
     auto* s1 = Structure("S1", utils::Vector{Member("x", ty.Of(s2))});
     auto* s0 = Structure("S0", utils::Vector{Member("x", ty.Of(s1))});
-    GlobalVar(Source{{12, 34}}, "g", ty.Of(s0), type::AddressSpace::kStorage, type::Access::kRead,
-              Group(0_a), Binding(0_a));
+    GlobalVar(Source{{12, 34}}, "g", ty.Of(s0), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Group(0_a), Binding(0_a));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 2e4084e..43e9929 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/ast/disable_validation_attribute.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/transform/add_block_attribute.h"
@@ -60,6 +61,7 @@
     kInterpolate,
     kInvariant,
     kLocation,
+    kMustUse,
     kOffset,
     kSize,
     kStage,
@@ -97,21 +99,23 @@
         case AttributeKind::kBuiltin:
             return {builder.Builtin(source, builtin::BuiltinValue::kPosition)};
         case AttributeKind::kDiagnostic:
-            return {builder.DiagnosticAttribute(source, ast::DiagnosticSeverity::kInfo,
+            return {builder.DiagnosticAttribute(source, builtin::DiagnosticSeverity::kInfo,
                                                 "chromium_unreachable_code")};
         case AttributeKind::kGroup:
             return {builder.Group(source, 1_a)};
         case AttributeKind::kId:
             return {builder.Id(source, 0_a)};
         case AttributeKind::kInterpolate:
-            return {builder.Interpolate(source, ast::InterpolationType::kLinear,
-                                        ast::InterpolationSampling::kCenter)};
+            return {builder.Interpolate(source, builtin::InterpolationType::kLinear,
+                                        builtin::InterpolationSampling::kCenter)};
         case AttributeKind::kInvariant:
             return {builder.Invariant(source)};
         case AttributeKind::kLocation:
             return {builder.Location(source, 1_a)};
         case AttributeKind::kOffset:
             return {builder.MemberOffset(source, 4_a)};
+        case AttributeKind::kMustUse:
+            return {builder.MustUse(source)};
         case AttributeKind::kSize:
             return {builder.MemberSize(source, 16_a)};
         case AttributeKind::kStage:
@@ -157,6 +161,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -194,6 +199,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -221,9 +227,9 @@
     } else {
         EXPECT_FALSE(r()->Resolve());
         if (params.kind == AttributeKind::kBuiltin) {
-            EXPECT_EQ(r()->error(),
-                      "12:34 error: builtin(position) cannot be used in input of "
-                      "compute pipeline stage");
+            EXPECT_EQ(
+                r()->error(),
+                R"(12:34 error: @builtin(position) cannot be used in input of compute pipeline stage)");
         } else if (params.kind == AttributeKind::kInterpolate ||
                    params.kind == AttributeKind::kLocation ||
                    params.kind == AttributeKind::kInvariant) {
@@ -245,6 +251,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -283,6 +290,7 @@
                                          // kInterpolate tested separately (requires @location)
                                          TestParams{AttributeKind::kInvariant, true},
                                          TestParams{AttributeKind::kLocation, true},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -314,9 +322,9 @@
     } else {
         EXPECT_FALSE(r()->Resolve());
         if (params.kind == AttributeKind::kBuiltin) {
-            EXPECT_EQ(r()->error(),
-                      "12:34 error: builtin(position) cannot be used in input of "
-                      "vertex pipeline stage");
+            EXPECT_EQ(
+                r()->error(),
+                R"(12:34 error: @builtin(position) cannot be used in input of vertex pipeline stage)");
         } else if (params.kind == AttributeKind::kInvariant) {
             EXPECT_EQ(r()->error(),
                       "12:34 error: invariant attribute must only be applied to a "
@@ -337,6 +345,7 @@
                                          TestParams{AttributeKind::kInterpolate, true},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, true},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -362,9 +371,9 @@
     } else {
         EXPECT_FALSE(r()->Resolve());
         if (params.kind == AttributeKind::kBuiltin) {
-            EXPECT_EQ(r()->error(),
-                      "12:34 error: builtin(position) cannot be used in output of "
-                      "compute pipeline stage");
+            EXPECT_EQ(
+                r()->error(),
+                R"(12:34 error: @builtin(position) cannot be used in output of compute pipeline stage)");
         } else if (params.kind == AttributeKind::kInterpolate ||
                    params.kind == AttributeKind::kLocation ||
                    params.kind == AttributeKind::kInvariant) {
@@ -388,6 +397,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -411,21 +421,20 @@
     } else {
         EXPECT_FALSE(r()->Resolve());
         if (params.kind == AttributeKind::kBuiltin) {
-            EXPECT_EQ(r()->error(),
-                      "12:34 error: builtin(position) cannot be used in output of "
-                      "fragment pipeline stage");
+            EXPECT_EQ(
+                r()->error(),
+                R"(12:34 error: @builtin(position) cannot be used in output of fragment pipeline stage)");
         } else if (params.kind == AttributeKind::kInvariant) {
-            EXPECT_EQ(r()->error(),
-                      "12:34 error: invariant attribute must only be applied to a "
-                      "position builtin");
+            EXPECT_EQ(
+                r()->error(),
+                R"(12:34 error: invariant attribute must only be applied to a position builtin)");
         } else if (params.kind == AttributeKind::kLocation) {
             EXPECT_EQ(r()->error(),
-                      "34:56 error: duplicate location attribute\n"
-                      "12:34 note: first attribute declared here");
+                      R"(34:56 error: duplicate location attribute
+12:34 note: first attribute declared here)");
         } else {
             EXPECT_EQ(r()->error(),
-                      "12:34 error: attribute is not valid for entry point return "
-                      "types");
+                      R"(12:34 error: attribute is not valid for entry point return types)");
         }
     }
 }
@@ -440,6 +449,7 @@
                                          TestParams{AttributeKind::kInterpolate, true},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -470,12 +480,11 @@
         EXPECT_FALSE(r()->Resolve());
         if (params.kind == AttributeKind::kLocation) {
             EXPECT_EQ(r()->error(),
-                      "34:56 error: multiple entry point IO attributes\n"
-                      "12:34 note: previously consumed location(1)");
+                      R"(34:56 error: multiple entry point IO attributes
+12:34 note: previously consumed @location)");
         } else {
             EXPECT_EQ(r()->error(),
-                      "12:34 error: attribute is not valid for entry point return "
-                      "types");
+                      R"(12:34 error: attribute is not valid for entry point return types)");
         }
     }
 }
@@ -490,6 +499,7 @@
                                          // kInterpolate tested separately (requires @location)
                                          TestParams{AttributeKind::kInvariant, true},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -594,6 +604,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -630,6 +641,7 @@
                                          // kInterpolate tested separately (requires @location)
                                          // kInvariant tested separately (requires position builtin)
                                          TestParams{AttributeKind::kLocation, true},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, true},
                                          TestParams{AttributeKind::kSize, true},
                                          TestParams{AttributeKind::kStage, false},
@@ -734,8 +746,8 @@
 }
 
 TEST_F(StructMemberAttributeTest, Align_Attribute_Var) {
-    GlobalVar(Source{{1, 2}}, "val", ty.f32(), type::AddressSpace::kPrivate,
-              type::Access::kUndefined, Expr(1.23_f));
+    GlobalVar(Source{{1, 2}}, "val", ty.f32(), builtin::AddressSpace::kPrivate,
+              builtin::Access::kUndefined, Expr(1.23_f));
 
     Structure(Source{{6, 4}}, "mystruct",
               utils::Vector{Member(Source{{12, 5}}, "a", ty.f32(),
@@ -808,8 +820,8 @@
 }
 
 TEST_F(StructMemberAttributeTest, Size_Attribute_Var) {
-    GlobalVar(Source{{1, 2}}, "val", ty.f32(), type::AddressSpace::kPrivate,
-              type::Access::kUndefined, Expr(1.23_f));
+    GlobalVar(Source{{1, 2}}, "val", ty.f32(), builtin::AddressSpace::kPrivate,
+              builtin::Access::kUndefined, Expr(1.23_f));
 
     Structure(Source{{6, 4}}, "mystruct",
               utils::Vector{Member(Source{{12, 5}}, "a", ty.f32(),
@@ -872,6 +884,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -888,7 +901,7 @@
     if (IsBindingAttribute(params.kind)) {
         GlobalVar("a", ty.sampler(type::SamplerKind::kSampler), attrs);
     } else {
-        GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate, attrs);
+        GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate, attrs);
     }
 
     if (params.should_pass) {
@@ -912,6 +925,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -964,6 +978,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -1008,6 +1023,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -1114,6 +1130,7 @@
                                          TestParams{AttributeKind::kInterpolate, false},
                                          TestParams{AttributeKind::kInvariant, false},
                                          TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kMustUse, false},
                                          TestParams{AttributeKind::kOffset, false},
                                          TestParams{AttributeKind::kSize, false},
                                          TestParams{AttributeKind::kStage, false},
@@ -1157,7 +1174,7 @@
                             create<ast::StrideAttribute>(Source{{12, 34}}, params.stride),
                         });
 
-    GlobalVar("myarray", arr, type::AddressSpace::kPrivate);
+    GlobalVar("myarray", arr, builtin::AddressSpace::kPrivate);
 
     if (params.should_pass) {
         EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1240,7 +1257,7 @@
                             create<ast::StrideAttribute>(Source{{56, 78}}, 4u),
                         });
 
-    GlobalVar("myarray", arr, type::AddressSpace::kPrivate);
+    GlobalVar("myarray", arr, builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -1259,7 +1276,7 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("x", ty.i32()),
                              });
-    GlobalVar(Source{{12, 34}}, "G", ty.Of(s), type::AddressSpace::kUniform);
+    GlobalVar(Source{{12, 34}}, "G", ty.Of(s), builtin::AddressSpace::kUniform);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -1270,7 +1287,8 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("x", ty.i32()),
                              });
-    GlobalVar(Source{{12, 34}}, "G", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead);
+    GlobalVar(Source{{12, 34}}, "G", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -1356,7 +1374,7 @@
 }
 
 TEST_F(ResourceAttributeTest, BindingPointOnNonResource) {
-    GlobalVar(Source{{12, 34}}, "G", ty.f32(), type::AddressSpace::kPrivate, Binding(1_a),
+    GlobalVar(Source{{12, 34}}, "G", ty.f32(), builtin::AddressSpace::kPrivate, Binding(1_a),
               Group(2_a));
 
     EXPECT_FALSE(r()->Resolve());
@@ -1413,6 +1431,24 @@
 }  // namespace
 }  // namespace InvariantAttributeTests
 
+namespace MustUseAttributeTests {
+namespace {
+
+using MustUseAttributeTests = ResolverTest;
+TEST_F(MustUseAttributeTests, MustUse) {
+    Func("main", utils::Empty, ty.vec4<f32>(),
+         utils::Vector{
+             Return(Call(ty.vec4<f32>())),
+         },
+         utils::Vector{
+             MustUse(Source{{12, 34}}),
+         });
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+}  // namespace
+}  // namespace MustUseAttributeTests
+
 namespace WorkgroupAttributeTests {
 namespace {
 
@@ -1446,9 +1482,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: the workgroup_size attribute is only valid for "
-              "compute stages");
+    EXPECT_EQ(r()->error(), "12:34 error: @workgroup_size is only valid for compute stages");
 }
 
 TEST_F(WorkgroupAttribute, NotAComputeShader) {
@@ -1459,9 +1493,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: the workgroup_size attribute is only valid for "
-              "compute stages");
+    EXPECT_EQ(r()->error(), "12:34 error: @workgroup_size is only valid for compute stages");
 }
 
 TEST_F(WorkgroupAttribute, DuplicateAttribute) {
@@ -1487,8 +1519,8 @@
 using InterpolateTest = ResolverTest;
 
 struct Params {
-    ast::InterpolationType type;
-    ast::InterpolationSampling sampling;
+    builtin::InterpolationType type;
+    builtin::InterpolationSampling sampling;
     bool should_pass;
 };
 
@@ -1537,7 +1569,7 @@
              Stage(ast::PipelineStage::kFragment),
          });
 
-    if (params.type != ast::InterpolationType::kFlat) {
+    if (params.type != builtin::InterpolationType::kFlat) {
         EXPECT_FALSE(r()->Resolve());
         EXPECT_EQ(r()->error(),
                   "12:34 error: interpolation type must be 'flat' for integral "
@@ -1568,7 +1600,7 @@
              Stage(ast::PipelineStage::kFragment),
          });
 
-    if (params.type != ast::InterpolationType::kFlat) {
+    if (params.type != builtin::InterpolationType::kFlat) {
         EXPECT_FALSE(r()->Resolve());
         EXPECT_EQ(r()->error(),
                   "12:34 error: interpolation type must be 'flat' for integral "
@@ -1587,19 +1619,25 @@
     ResolverAttributeValidationTest,
     InterpolateParameterTest,
     testing::Values(
-        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kUndefined, true},
-        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCenter, true},
-        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCentroid, true},
-        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kSample, true},
-        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kUndefined, true},
-        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kCenter, true},
-        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kCentroid, true},
-        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kSample, true},
+        Params{builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kUndefined,
+               true},
+        Params{builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kCenter,
+               true},
+        Params{builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kCentroid,
+               true},
+        Params{builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kSample,
+               true},
+        Params{builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kUndefined,
+               true},
+        Params{builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCenter, true},
+        Params{builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCentroid,
+               true},
+        Params{builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kSample, true},
         // flat interpolation must not have a sampling type
-        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kUndefined, true},
-        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kCenter, false},
-        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kCentroid, false},
-        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kSample, false}));
+        Params{builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kUndefined, true},
+        Params{builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kCenter, false},
+        Params{builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kCentroid, false},
+        Params{builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kSample, false}));
 
 TEST_F(InterpolateTest, FragmentInput_Integer_MissingFlatInterpolation) {
     Func("main",
@@ -1643,8 +1681,7 @@
              Param("a", ty.vec4<f32>(),
                    utils::Vector{
                        Builtin(builtin::BuiltinValue::kPosition),
-                       Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                                   ast::InterpolationSampling::kUndefined),
+                       Interpolate(Source{{12, 34}}, builtin::InterpolationType::kFlat),
                    }),
          },
          ty.void_(), utils::Empty,
@@ -1667,8 +1704,7 @@
          },
          utils::Vector{
              Builtin(builtin::BuiltinValue::kPosition),
-             Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                         ast::InterpolationSampling::kUndefined),
+             Interpolate(Source{{12, 34}}, builtin::InterpolationType::kFlat),
          });
 
     EXPECT_FALSE(r()->Resolve());
@@ -1677,12 +1713,12 @@
 }
 
 TEST_F(InterpolateTest, MissingLocationAttribute_Struct) {
-    Structure("S",
-              utils::Vector{
-                  Member("a", ty.f32(),
-                         utils::Vector{Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                                                   ast::InterpolationSampling::kUndefined)}),
-              });
+    Structure(
+        "S",
+        utils::Vector{
+            Member("a", ty.f32(),
+                   utils::Vector{Interpolate(Source{{12, 34}}, builtin::InterpolationType::kFlat)}),
+        });
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -1924,4 +1960,20 @@
 }  // namespace
 }  // namespace InterpolateTests
 
+namespace MustUseTests {
+namespace {
+
+using MustUseAttributeTest = ResolverTest;
+TEST_F(MustUseAttributeTest, UsedOnFnWithNoReturnValue) {
+    Func("fn_must_use", utils::Empty, ty.void_(), utils::Empty,
+         utils::Vector{MustUse(Source{{12, 34}})});
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: @must_use can only be applied to functions that return a value)");
+}
+
+}  // namespace
+}  // namespace MustUseTests
+
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index e3becab..6a9e5a3 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -81,7 +81,7 @@
 TEST_P(ResolverBuiltinTest_BoolMethod, Scalar) {
     auto name = GetParam();
 
-    GlobalVar("my_var", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call(name, "my_var");
     WrapInFunction(expr);
@@ -94,7 +94,7 @@
 TEST_P(ResolverBuiltinTest_BoolMethod, Vector) {
     auto name = GetParam();
 
-    GlobalVar("my_var", ty.vec3<bool>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec3<bool>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call(name, "my_var");
     WrapInFunction(expr);
@@ -109,9 +109,9 @@
                          testing::Values("any", "all"));
 
 TEST_F(ResolverBuiltinTest, Select) {
-    GlobalVar("my_var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    GlobalVar("bool_var", ty.vec3<bool>(), type::AddressSpace::kPrivate);
+    GlobalVar("bool_var", ty.vec3<bool>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("select", "my_var", "my_var", "bool_var");
     WrapInFunction(expr);
@@ -215,8 +215,8 @@
 TEST_F(ResolverBuiltinArrayTest, ArrayLength_Vector) {
     auto ary = ty.array<i32>();
     auto* str = Structure("S", utils::Vector{Member("x", ary)});
-    GlobalVar("a", ty.Of(str), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
-              Group(0_a));
+    GlobalVar("a", ty.Of(str), builtin::AddressSpace::kStorage, builtin::Access::kRead,
+              Binding(0_a), Group(0_a));
 
     auto* call = Call("arrayLength", AddressOf(MemberAccessor("a", "x")));
     WrapInFunction(call);
@@ -228,7 +228,7 @@
 }
 
 TEST_F(ResolverBuiltinArrayTest, ArrayLength_Error_ArraySized) {
-    GlobalVar("arr", ty.array<i32, 4>(), type::AddressSpace::kPrivate);
+    GlobalVar("arr", ty.array<i32, 4>(), builtin::AddressSpace::kPrivate);
     auto* call = Call("arrayLength", AddressOf("arr"));
     WrapInFunction(call);
 
@@ -1048,7 +1048,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Frexp_Error_FirstParamInt) {
-    GlobalVar("v", ty.i32(), type::AddressSpace::kWorkgroup);
+    GlobalVar("v", ty.i32(), builtin::AddressSpace::kWorkgroup);
     auto* call = Call("frexp", 1_i, AddressOf("v"));
     WrapInFunction(call);
 
@@ -1297,7 +1297,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Modf_Error_FirstParamInt) {
-    GlobalVar("whole", ty.f32(), type::AddressSpace::kWorkgroup);
+    GlobalVar("whole", ty.f32(), builtin::AddressSpace::kWorkgroup);
     auto* call = Call("modf", 1_i, AddressOf("whole"));
     WrapInFunction(call);
 
@@ -1313,7 +1313,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Modf_Error_SecondParamIntPtr) {
-    GlobalVar("whole", ty.i32(), type::AddressSpace::kWorkgroup);
+    GlobalVar("whole", ty.i32(), builtin::AddressSpace::kWorkgroup);
     auto* call = Call("modf", 1_f, AddressOf("whole"));
     WrapInFunction(call);
 
@@ -1343,7 +1343,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Modf_Error_VectorSizesDontMatch) {
-    GlobalVar("whole", ty.vec4<f32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("whole", ty.vec4<f32>(), builtin::AddressSpace::kWorkgroup);
     auto* call = Call("modf", vec2<f32>(1_f, 2_f), AddressOf("whole"));
     WrapInFunction(call);
 
@@ -1823,7 +1823,7 @@
 namespace matrix_builtin_tests {
 
 TEST_F(ResolverBuiltinTest, Determinant_2x2_f32) {
-    GlobalVar("var", ty.mat2x2<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat2x2<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("determinant", "var");
     WrapInFunction(call);
@@ -1837,7 +1837,7 @@
 TEST_F(ResolverBuiltinTest, Determinant_2x2_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("var", ty.mat2x2<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat2x2<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("determinant", "var");
     WrapInFunction(call);
@@ -1849,7 +1849,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_3x3_f32) {
-    GlobalVar("var", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("determinant", "var");
     WrapInFunction(call);
@@ -1863,7 +1863,7 @@
 TEST_F(ResolverBuiltinTest, Determinant_3x3_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("var", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("determinant", "var");
     WrapInFunction(call);
@@ -1875,7 +1875,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_4x4_f32) {
-    GlobalVar("var", ty.mat4x4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat4x4<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("determinant", "var");
     WrapInFunction(call);
@@ -1889,7 +1889,7 @@
 TEST_F(ResolverBuiltinTest, Determinant_4x4_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("var", ty.mat4x4<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat4x4<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("determinant", "var");
     WrapInFunction(call);
@@ -1901,7 +1901,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_NotSquare) {
-    GlobalVar("var", ty.mat2x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat2x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("determinant", "var");
     WrapInFunction(call);
@@ -1916,7 +1916,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_NotMatrix) {
-    GlobalVar("var", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("determinant", "var");
     WrapInFunction(call);
@@ -1936,7 +1936,7 @@
 namespace vector_builtin_tests {
 
 TEST_F(ResolverBuiltinTest, Dot_Vec2_f32) {
-    GlobalVar("my_var", ty.vec2<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("dot", "my_var", "my_var");
     WrapInFunction(expr);
@@ -1950,7 +1950,7 @@
 TEST_F(ResolverBuiltinTest, Dot_Vec2_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("my_var", ty.vec2<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec2<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("dot", "my_var", "my_var");
     WrapInFunction(expr);
@@ -1962,7 +1962,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Dot_Vec3_i32) {
-    GlobalVar("my_var", ty.vec3<i32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("dot", "my_var", "my_var");
     WrapInFunction(expr);
@@ -1974,7 +1974,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Dot_Vec4_u32) {
-    GlobalVar("my_var", ty.vec4<u32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_var", ty.vec4<u32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("dot", "my_var", "my_var");
     WrapInFunction(expr);
@@ -2009,7 +2009,7 @@
 TEST_P(ResolverBuiltinDerivativeTest, Scalar) {
     auto name = GetParam();
 
-    GlobalVar("ident", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("ident", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call(name, "ident");
     Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
@@ -2023,7 +2023,7 @@
 
 TEST_P(ResolverBuiltinDerivativeTest, Vector) {
     auto name = GetParam();
-    GlobalVar("ident", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("ident", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call(name, "ident");
     Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
@@ -2083,7 +2083,7 @@
 struct TextureTestParams {
     type::TextureDimension dim;
     Texture type = Texture::kF32;
-    type::TexelFormat format = type::TexelFormat::kR32Float;
+    builtin::TexelFormat format = builtin::TexelFormat::kR32Float;
 };
 inline std::ostream& operator<<(std::ostream& out, TextureTestParams data) {
     out << data.dim << "_" << data.type;
@@ -2119,7 +2119,7 @@
         if (utils::HasPrefix(type_name, "texture") || utils::HasPrefix(type_name, "sampler")) {
             GlobalVar(name, type, Binding(0_a), Group(0_a));
         } else {
-            GlobalVar(name, type, type::AddressSpace::kPrivate);
+            GlobalVar(name, type, builtin::AddressSpace::kPrivate);
         }
 
         call_params->Push(Expr(name));
@@ -2438,7 +2438,8 @@
     param.BuildSamplerVariable(this);
 
     auto* call = Call(param.function, param.args(this));
-    auto* stmt = CallStmt(call);
+    auto* stmt = param.returns_value ? static_cast<const ast::Statement*>(Assign(Phony(), call))
+                                     : static_cast<const ast::Statement*>(CallStmt(call));
     Func("func", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
 
diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc
index 22e13c2..967335d 100644
--- a/src/tint/resolver/builtin_validation_test.cc
+++ b/src/tint/resolver/builtin_validation_test.cc
@@ -16,7 +16,7 @@
 
 #include "src/tint/ast/builtin_texture_helper_test.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -42,7 +42,7 @@
     auto* dpdx = Call(Source{{3, 4}}, "dpdx", 1_f);
     Func(Source{{1, 2}}, "func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(dpdx),
+             Assign(Phony(), dpdx),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -62,7 +62,7 @@
     auto* dpdx = Call(Source{{3, 4}}, "dpdx", 1_f);
     Func(Source{{1, 2}}, "f0", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(dpdx),
+             Assign(Phony(), dpdx),
          });
 
     Func(Source{{3, 4}}, "f1", utils::Empty, ty.void_(),
@@ -132,7 +132,7 @@
 
 TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalVarUsedAsVariable) {
     auto* mix =
-        GlobalVar(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i), type::AddressSpace::kPrivate);
+        GlobalVar(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i), builtin::AddressSpace::kPrivate);
     auto* use = Expr("mix");
     WrapInFunction(Decl(Var("v", use)));
 
@@ -147,9 +147,9 @@
     WrapInFunction(Call(Source{{56, 78}}, "mix", 1_f, 2_f, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(56:78 error: no matching initializer for i32(f32, f32, f32)
+    EXPECT_EQ(r()->error(), R"(56:78 error: no matching constructor for i32(f32, f32, f32)
 
-2 candidate initializers:
+2 candidate constructors:
   i32(i32) -> i32
   i32() -> i32
 
@@ -177,7 +177,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: struct initializer has too many inputs: expected 1, found 3)");
+              R"(12:34 error: structure constructor has too many inputs: expected 1, found 3)");
 }
 
 TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsStructUsedAsType) {
@@ -309,8 +309,8 @@
     auto args = overload.args(this);
     auto*& arg_to_replace = (param.position == Position::kFirst) ? args.Front() : args.Back();
 
-    // BuildTextureVariable() uses a Literal for scalars, and a CallExpression for
-    // a vector initializer.
+    // BuildTextureVariable() uses a Literal for scalars, and a CallExpression for a vector
+    // constructor.
     bool is_vector = arg_to_replace->Is<ast::CallExpression>();
 
     // Make the expression to be replaced, reachable. This keeps the resolver happy.
@@ -318,10 +318,14 @@
 
     arg_to_replace = expr(Source{{12, 34}}, *this);
 
+    auto* call = Call(overload.function, args);
+    auto* stmt = overload.returns_value ? static_cast<const ast::Statement*>(Assign(Phony(), call))
+                                        : static_cast<const ast::Statement*>(CallStmt(call));
+
     // Call the builtin with the constexpr argument replaced
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call(overload.function, args)),
+             stmt,
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -362,8 +366,8 @@
     auto args = overload.args(this);
     auto*& arg_to_replace = (param.position == Position::kFirst) ? args.Front() : args.Back();
 
-    // BuildTextureVariable() uses a Literal for scalars, and a CallExpression for
-    // a vector initializer.
+    // BuildTextureVariable() uses a Literal for scalars, and a CallExpression for a vector
+    // constructor.
     bool is_vector = arg_to_replace->Is<ast::CallExpression>();
 
     // Make the expression to be replaced, reachable. This keeps the resolver happy.
@@ -371,10 +375,14 @@
 
     arg_to_replace = Expr(Source{{12, 34}}, "G");
 
+    auto* call = Call(overload.function, args);
+    auto* stmt = overload.returns_value ? static_cast<const ast::Statement*>(Assign(Phony(), call))
+                                        : static_cast<const ast::Statement*>(CallStmt(call));
+
     // Call the builtin with the constant-expression argument replaced
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call(overload.function, args)),
+             stmt,
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -410,7 +418,7 @@
     overload.BuildSamplerVariable(this);
 
     // Build the module-scope var 'G' with the offset value
-    GlobalVar("G", expr({}, *this), type::AddressSpace::kPrivate);
+    GlobalVar("G", expr({}, *this), builtin::AddressSpace::kPrivate);
 
     auto args = overload.args(this);
     auto*& arg_to_replace = (param.position == Position::kFirst) ? args.Front() : args.Back();
@@ -420,10 +428,14 @@
 
     arg_to_replace = Expr(Source{{12, 34}}, "G");
 
+    auto* call = Call(overload.function, args);
+    auto* stmt = overload.returns_value ? static_cast<const ast::Statement*>(Assign(Phony(), call))
+                                        : static_cast<const ast::Statement*>(CallStmt(call));
+
     // Call the builtin with the constant-expression argument replaced
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call(overload.function, args)),
+             stmt,
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -581,7 +593,7 @@
     // fn foo() {
     //   workgroupUniformLoad(&v);
     // }
-    GlobalVar("v", ty.i32(), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("v", ty.i32(), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               utils::Vector{Group(0_a), Binding(0_a)});
     WrapInFunction(CallStmt(Call("workgroupUniformLoad", AddressOf(Source{{12, 34}}, "v"))));
 
@@ -599,7 +611,7 @@
     // fn foo() {
     //   workgroupUniformLoad(&v);
     // }
-    GlobalVar("v", ty.atomic<i32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("v", ty.atomic<i32>(), builtin::AddressSpace::kWorkgroup);
     WrapInFunction(CallStmt(Call("workgroupUniformLoad", AddressOf(Source{{12, 34}}, "v"))));
 
     EXPECT_FALSE(r()->Resolve());
@@ -613,7 +625,7 @@
     // fn foo() {
     //   workgroupUniformLoad(&v);
     // }
-    GlobalVar("v", ty.array(ty.atomic<i32>(), 4_a), type::AddressSpace::kWorkgroup);
+    GlobalVar("v", ty.array(ty.atomic<i32>(), 4_a), builtin::AddressSpace::kWorkgroup);
     WrapInFunction(CallStmt(Call("workgroupUniformLoad", AddressOf(Source{{12, 34}}, "v"))));
 
     EXPECT_FALSE(r()->Resolve());
@@ -631,7 +643,7 @@
     // }
     Structure("Inner", utils::Vector{Member("a", ty.array(ty.atomic<i32>(), 4_a))});
     Structure("S", utils::Vector{Member("i", ty("Inner"))});
-    GlobalVar(Source{{12, 34}}, "v", ty.array(ty("S"), 4_a), type::AddressSpace::kWorkgroup);
+    GlobalVar(Source{{12, 34}}, "v", ty.array(ty("S"), 4_a), builtin::AddressSpace::kWorkgroup);
     WrapInFunction(CallStmt(Call("workgroupUniformLoad", AddressOf("v"))));
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc
index 0921c2e..63e5abf 100644
--- a/src/tint/resolver/builtins_validation_test.cc
+++ b/src/tint/resolver/builtins_validation_test.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/ast/call_statement.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
 using namespace tint::number_suffixes;  // NOLINT
@@ -112,7 +113,7 @@
 TEST_P(ResolverBuiltinsStageTest, All_input) {
     const Params& params = GetParam();
 
-    auto* p = GlobalVar("p", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    auto* p = GlobalVar("p", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
     auto* input = Param("input", params.type(*this),
                         utils::Vector{Builtin(Source{{12, 34}}, params.builtin)});
     switch (params.stage) {
@@ -145,7 +146,7 @@
         EXPECT_TRUE(r()->Resolve()) << r()->error();
     } else {
         std::stringstream err;
-        err << "12:34 error: builtin(" << params.builtin << ")";
+        err << "12:34 error: @builtin(" << params.builtin << ")";
         err << " cannot be used in input of " << params.stage << " pipeline stage";
         EXPECT_FALSE(r()->Resolve());
         EXPECT_EQ(r()->error(), err.str());
@@ -178,9 +179,9 @@
              Location(0_a),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: builtin(frag_depth) cannot be used in input of "
-              "fragment pipeline stage");
+    EXPECT_EQ(
+        r()->error(),
+        "12:34 error: @builtin(frag_depth) cannot be used in input of fragment pipeline stage");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInputStruct_Fail) {
@@ -214,7 +215,7 @@
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: builtin(frag_depth) cannot be used in input of "
+              "12:34 error: @builtin(frag_depth) cannot be used in input of "
               "fragment pipeline stage\n"
               "note: while analyzing entry point 'fragShader'");
 }
@@ -272,7 +273,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(position) must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_ReturnType_Fail) {
@@ -288,7 +289,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(position) must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthNotF32_Struct_Fail) {
@@ -317,7 +318,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(frag_depth) must be 'f32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(frag_depth) must be 'f32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_Struct_Fail) {
@@ -346,7 +347,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_mask) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_ReturnType_Fail) {
@@ -361,7 +362,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_mask) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskIsNotU32_Fail) {
@@ -387,7 +388,7 @@
              Location(0_a),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_mask) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Struct_Fail) {
@@ -416,7 +417,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_index) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_index) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Fail) {
@@ -442,7 +443,7 @@
              Location(0_a),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_index) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_index) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, PositionIsNotF32_Fail) {
@@ -468,7 +469,7 @@
              Location(0_a),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(position) must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthIsNotF32_Fail) {
@@ -487,7 +488,7 @@
              Builtin(Source{{12, 34}}, builtin::BuiltinValue::kFragDepth),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(frag_depth) must be 'f32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(frag_depth) must be 'f32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, VertexIndexIsNotU32_Fail) {
@@ -512,7 +513,7 @@
              Builtin(builtin::BuiltinValue::kPosition),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(vertex_index) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(vertex_index) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, InstanceIndexIsNotU32) {
@@ -537,7 +538,7 @@
              Builtin(builtin::BuiltinValue::kPosition),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(instance_index) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(instance_index) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltin_Pass) {
@@ -657,7 +658,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of builtin(workgroup_id) must be "
+              "12:34 error: store type of @builtin(workgroup_id) must be "
               "'vec3<u32>'");
 }
 
@@ -672,7 +673,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of builtin(num_workgroups) must be "
+              "12:34 error: store type of @builtin(num_workgroups) must be "
               "'vec3<u32>'");
 }
 
@@ -687,7 +688,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of builtin(global_invocation_id) must be "
+              "12:34 error: store type of @builtin(global_invocation_id) must be "
               "'vec3<u32>'");
 }
 
@@ -703,7 +704,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of builtin(local_invocation_index) must be "
+              "12:34 error: store type of @builtin(local_invocation_index) must be "
               "'u32'");
 }
 
@@ -718,7 +719,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of builtin(local_invocation_id) must be "
+              "12:34 error: store type of @builtin(local_invocation_id) must be "
               "'vec3<u32>'");
 }
 
@@ -785,7 +786,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(front_facing) must be 'bool'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(front_facing) must be 'bool'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FrontFacingMemberIsNotBool_Fail) {
@@ -814,7 +815,50 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(front_facing) must be 'bool'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(front_facing) must be 'bool'");
+}
+
+// TODO(crbug.com/tint/1846): This isn't a validation test, but this sits next to other @builtin
+// tests. Clean this up.
+TEST_F(ResolverBuiltinsValidationTest, StructMemberAttributeMapsToSemBuiltinEnum) {
+    // struct S {
+    //   @builtin(front_facing) b : bool;
+    // };
+    // @fragment
+    // fn f(s : S) {}
+
+    auto* builtin = Builtin(builtin::BuiltinValue::kFrontFacing);
+    auto* s = Structure("S", utils::Vector{
+                                 Member("f", ty.bool_(), utils::Vector{builtin}),
+                             });
+    Func("f", utils::Vector{Param("b", ty.Of(s))}, ty.void_(), utils::Empty,
+         utils::Vector{
+             Stage(ast::PipelineStage::kFragment),
+         });
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* builtin_expr = Sem().Get(builtin);
+    ASSERT_NE(builtin_expr, nullptr);
+    EXPECT_EQ(builtin_expr->Value(), builtin::BuiltinValue::kFrontFacing);
+}
+
+// TODO(crbug.com/tint/1846): This isn't a validation test, but this sits next to other @builtin
+// tests. Clean this up.
+TEST_F(ResolverBuiltinsValidationTest, ParamAttributeMapsToSemBuiltinEnum) {
+    // @fragment
+    // fn f(@builtin(front_facing) b : bool) {}
+
+    auto* builtin = Builtin(builtin::BuiltinValue::kFrontFacing);
+    Func("f", utils::Vector{Param("b", ty.bool_(), utils::Vector{builtin})}, ty.void_(),
+         utils::Empty,
+         utils::Vector{
+             Stage(ast::PipelineStage::kFragment),
+         });
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* builtin_expr = Sem().Get(builtin);
+    ASSERT_NE(builtin_expr, nullptr);
+    EXPECT_EQ(builtin_expr->Value(), builtin::BuiltinValue::kFrontFacing);
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Length_Float_Scalar) {
@@ -1117,7 +1161,7 @@
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(builtin),
+             Assign(Phony(), builtin),
          },
          utils::Vector{
              create<ast::StageAttribute>(ast::PipelineStage::kFragment),
@@ -1138,7 +1182,7 @@
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(builtin),
+             Assign(Phony(), builtin),
          },
          utils::Vector{
              create<ast::StageAttribute>(ast::PipelineStage::kFragment),
@@ -1159,7 +1203,7 @@
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(builtin),
+             Assign(Phony(), builtin),
          },
          utils::Vector{
              create<ast::StageAttribute>(ast::PipelineStage::kFragment),
@@ -1180,7 +1224,7 @@
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(builtin),
+             Assign(Phony(), builtin),
          },
          utils::Vector{
              create<ast::StageAttribute>(ast::PipelineStage::kFragment),
diff --git a/src/tint/resolver/call_validation_test.cc b/src/tint/resolver/call_validation_test.cc
index b0b8cce..b749df9 100644
--- a/src/tint/resolver/call_validation_test.cc
+++ b/src/tint/resolver/call_validation_test.cc
@@ -103,7 +103,7 @@
     //   var z: i32 = 1i;
     //   foo(&z);
     // }
-    auto* param = Param("p", ty.pointer<i32>(type::AddressSpace::kFunction));
+    auto* param = Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction));
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -120,7 +120,7 @@
     //   let z: i32 = 1i;
     //   foo(&z);
     // }
-    auto* param = Param("p", ty.pointer<i32>(type::AddressSpace::kFunction));
+    auto* param = Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction));
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -142,7 +142,7 @@
     auto* S = Structure("S", utils::Vector{
                                  Member("m", ty.i32()),
                              });
-    auto* param = Param("p", ty.pointer<i32>(type::AddressSpace::kFunction));
+    auto* param = Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction));
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -169,7 +169,7 @@
     auto* S = Structure("S", utils::Vector{
                                  Member("m", ty.i32()),
                              });
-    auto* param = Param("p", ty.pointer<i32>(type::AddressSpace::kFunction));
+    auto* param = Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction));
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -189,7 +189,7 @@
     auto* S = Structure("S", utils::Vector{
                                  Member("m", ty.i32()),
                              });
-    auto* param = Param("p", ty.pointer<i32>(type::AddressSpace::kFunction));
+    auto* param = Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction));
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -208,12 +208,12 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(), utils::Empty);
     Func("bar",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
@@ -235,12 +235,12 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(), utils::Empty);
     Func("bar",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(),
          utils::Vector{
@@ -268,13 +268,13 @@
     // }
     Func("x",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Var("v", ty.i32())),
-             Decl(Let("p", ty.pointer(ty.i32(), type::AddressSpace::kFunction), AddressOf("v"))),
+             Decl(Let("p", ty.pointer(ty.i32(), builtin::AddressSpace::kFunction), AddressOf("v"))),
              CallStmt(Call("x", "p")),
          },
          utils::Vector{
@@ -293,13 +293,13 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
          },
          ty.void_(), utils::Empty);
-    GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             Decl(Let("p", ty.pointer(ty.i32(), type::AddressSpace::kPrivate), AddressOf("v"))),
+             Decl(Let("p", ty.pointer(ty.i32(), builtin::AddressSpace::kPrivate), AddressOf("v"))),
              CallStmt(Call("foo", Expr(Source{{12, 34}}, "p"))),
          },
          utils::Vector{
@@ -318,13 +318,13 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Var("v", ty.array<i32, 4>())),
-             Decl(Let("p", ty.pointer(ty.i32(), type::AddressSpace::kFunction),
+             Decl(Let("p", ty.pointer(ty.i32(), builtin::AddressSpace::kFunction),
                       AddressOf(IndexAccessor("v", 0_a)))),
              CallStmt(Call("foo", Expr(Source{{12, 34}}, "p"))),
          },
@@ -349,13 +349,13 @@
     Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Var("v", ty.array<i32, 4>())),
-             Decl(Let("p", ty.pointer(ty.i32(), type::AddressSpace::kFunction),
+             Decl(Let("p", ty.pointer(ty.i32(), builtin::AddressSpace::kFunction),
                       AddressOf(IndexAccessor("v", 0_a)))),
              CallStmt(Call("foo", Expr(Source{{12, 34}}, "p"))),
          },
@@ -377,7 +377,7 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer(ty.array<i32, 4>(), type::AddressSpace::kFunction)),
+             Param("p", ty.pointer(ty.array<i32, 4>(), builtin::AddressSpace::kFunction)),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
@@ -406,7 +406,7 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
@@ -440,7 +440,7 @@
     Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     Func("foo",
          utils::Vector{
-             Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
+             Param("p", ty.pointer<i32>(builtin::AddressSpace::kFunction)),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
@@ -457,5 +457,26 @@
     EXPECT_TRUE(r()->Resolve());
 }
 
+TEST_F(ResolverCallValidationTest, MustUseFunction) {
+    Func(Source{{56, 78}}, "fn_must_use", utils::Empty, ty.i32(), utils::Vector{Return(1_i)},
+         utils::Vector{MustUse()});
+    Func("f", utils::Empty, ty.void_(),
+         utils::Vector{CallStmt(Call(Source{{12, 34}}, "fn_must_use"))});
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: ignoring return value of function 'fn_must_use' annotated with @must_use
+56:78 note: function 'fn_must_use' declared here)");
+}
+
+TEST_F(ResolverCallValidationTest, MustUseBuiltin) {
+    Func("f", utils::Empty, ty.void_(),
+         utils::Vector{CallStmt(Call(Source{{12, 34}}, "max", 1_a, 2_a))});
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: ignoring return value of builtin 'max'");
+}
+
 }  // namespace
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/compound_assignment_validation_test.cc b/src/tint/resolver/compound_assignment_validation_test.cc
index 64a542c..ee18de3 100644
--- a/src/tint/resolver/compound_assignment_validation_test.cc
+++ b/src/tint/resolver/compound_assignment_validation_test.cc
@@ -51,7 +51,7 @@
     // var a : i32;
     // let b : ptr<function,i32> = &a;
     // *b += 2;
-    const auto func = type::AddressSpace::kFunction;
+    const auto func = builtin::AddressSpace::kFunction;
     auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
     auto* var_b = Let("b", ty.pointer<i32>(func), AddressOf(Expr("a")));
     WrapInFunction(var_a, var_b,
@@ -233,8 +233,8 @@
     // {
     //   a += 1i;
     // }
-    GlobalVar(Source{{12, 34}}, "a", ty.i32(), type::AddressSpace::kStorage, type::Access::kRead,
-              Group(0_a), Binding(0_a));
+    GlobalVar(Source{{12, 34}}, "a", ty.i32(), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Group(0_a), Binding(0_a));
     WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", 1_i, ast::BinaryOp::kAdd));
 
     EXPECT_FALSE(r()->Resolve());
@@ -242,15 +242,16 @@
               "56:78 error: cannot store into a read-only type 'ref<storage, i32, read>'");
 }
 
-TEST_F(ResolverCompoundAssignmentValidationTest, LhsConstant) {
+TEST_F(ResolverCompoundAssignmentValidationTest, LhsLet) {
     // let a = 1i;
     // a += 1i;
     auto* a = Let(Source{{12, 34}}, "a", Expr(1_i));
     WrapInFunction(a, CompoundAssign(Expr(Source{{56, 78}}, "a"), 1_i, ast::BinaryOp::kAdd));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to 'let'
-12:34 note: 'a' is declared here:)");
+    EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to let 'a'
+56:78 note: 'let' variables are immutable
+12:34 note: let 'a' declared here)");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, LhsLiteral) {
@@ -258,13 +259,13 @@
     WrapInFunction(CompoundAssign(Expr(Source{{56, 78}}, 1_i), 1_i, ast::BinaryOp::kAdd));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "56:78 error: cannot assign to value of type 'i32'");
+    EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to value expression of type 'i32')");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, LhsAtomic) {
     // var<workgroup> a : atomic<i32>;
     // a += a;
-    GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), type::AddressSpace::kWorkgroup);
+    GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), builtin::AddressSpace::kWorkgroup);
     WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", "a", ast::BinaryOp::kAdd));
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/const_assert_test.cc b/src/tint/resolver/const_assert_test.cc
index fb08b8b..9b072f9 100644
--- a/src/tint/resolver/const_assert_test.cc
+++ b/src/tint/resolver/const_assert_test.cc
@@ -84,7 +84,7 @@
 }
 
 TEST_F(ResolverConstAssertTest, Local_NonConst) {
-    GlobalVar("V", ty.bool_(), Expr(true), type::AddressSpace::kPrivate);
+    GlobalVar("V", ty.bool_(), Expr(true), builtin::AddressSpace::kPrivate);
     WrapInFunction(ConstAssert(Expr(Source{{12, 34}}, "V")));
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index 741c9d8..dc59ccd 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -29,7 +29,7 @@
 #include "src/tint/number.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/member_accessor_expression.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
 #include "src/tint/type/abstract_float.h"
 #include "src/tint/type/abstract_int.h"
 #include "src/tint/type/array.h"
@@ -1228,18 +1228,18 @@
         });
 }
 
-ConstEval::Result ConstEval::ArrayOrStructInit(const type::Type* ty,
+ConstEval::Result ConstEval::ArrayOrStructCtor(const type::Type* ty,
                                                utils::VectorRef<const sem::ValueExpression*> args) {
     if (args.IsEmpty()) {
         return ZeroValue(ty);
     }
 
     if (args.Length() == 1 && args[0]->Type() == ty) {
-        // Identity initializer.
+        // Identity constructor.
         return args[0]->ConstantValue();
     }
 
-    // Multiple arguments. Must be a type initializer.
+    // Multiple arguments. Must be a value constructor.
     utils::Vector<const constant::Value*, 4> els;
     els.Reserve(args.Length());
     for (auto* arg : args) {
diff --git a/src/tint/resolver/const_eval.h b/src/tint/resolver/const_eval.h
index 934924e..969cfe7 100644
--- a/src/tint/resolver/const_eval.h
+++ b/src/tint/resolver/const_eval.h
@@ -80,7 +80,7 @@
     /// @param ty the target type - must be an array or initializer
     /// @param args the input arguments
     /// @return the constructed value, or null if the value cannot be calculated
-    Result ArrayOrStructInit(const type::Type* ty,
+    Result ArrayOrStructCtor(const type::Type* ty,
                              utils::VectorRef<const sem::ValueExpression*> args);
 
     /// @param ty the target type
@@ -127,7 +127,7 @@
     // Constant value evaluation methods, to be indirectly called via the intrinsic table
     ////////////////////////////////////////////////////////////////////////////////////////////////
 
-    /// Type conversion
+    /// Value conversion
     /// @param ty the result type
     /// @param args the input arguments
     /// @param source the source location
@@ -136,7 +136,7 @@
                 utils::VectorRef<const constant::Value*> args,
                 const Source& source);
 
-    /// Zero value type initializer
+    /// Zero value constructor
     /// @param ty the result type
     /// @param args the input arguments (no arguments provided)
     /// @param source the source location
@@ -145,7 +145,7 @@
                 utils::VectorRef<const constant::Value*> args,
                 const Source& source);
 
-    /// Identity value type initializer
+    /// Identity value constructor
     /// @param ty the result type
     /// @param args the input arguments
     /// @param source the source location
@@ -154,7 +154,7 @@
                     utils::VectorRef<const constant::Value*> args,
                     const Source& source);
 
-    /// Vector splat initializer
+    /// Vector splat constructor
     /// @param ty the vector type
     /// @param args the input arguments
     /// @param source the source location
@@ -163,7 +163,7 @@
                     utils::VectorRef<const constant::Value*> args,
                     const Source& source);
 
-    /// Vector initializer using scalars
+    /// Vector constructor using scalars
     /// @param ty the vector type
     /// @param args the input arguments
     /// @param source the source location
@@ -172,7 +172,7 @@
                     utils::VectorRef<const constant::Value*> args,
                     const Source& source);
 
-    /// Vector initializer using a mix of scalars and smaller vectors
+    /// Vector constructor using a mix of scalars and smaller vectors
     /// @param ty the vector type
     /// @param args the input arguments
     /// @param source the source location
@@ -181,7 +181,7 @@
                     utils::VectorRef<const constant::Value*> args,
                     const Source& source);
 
-    /// Matrix initializer using scalar values
+    /// Matrix constructor using scalar values
     /// @param ty the matrix type
     /// @param args the input arguments
     /// @param source the source location
@@ -190,7 +190,7 @@
                     utils::VectorRef<const constant::Value*> args,
                     const Source& source);
 
-    /// Matrix initializer using column vectors
+    /// Matrix constructor using column vectors
     /// @param ty the matrix type
     /// @param args the input arguments
     /// @param source the source location
diff --git a/src/tint/resolver/const_eval_binary_op_test.cc b/src/tint/resolver/const_eval_binary_op_test.cc
index ef7453e..e2dec19 100644
--- a/src/tint/resolver/const_eval_binary_op_test.cc
+++ b/src/tint/resolver/const_eval_binary_op_test.cc
@@ -1876,7 +1876,7 @@
 }
 
 ////////////////////////////////////////////////
-// Short-Circuit Type Init/Convert
+// Short-Circuit value construction / conversion
 ////////////////////////////////////////////////
 
 // NOTE: Cannot demonstrate short-circuiting an invalid init/convert as const eval of init/convert
@@ -1892,9 +1892,9 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: no matching initializer for vec2<f32>(abstract-float, bool)
+              R"(12:34 error: no matching constructor for vec2<f32>(abstract-float, bool)
 
-4 candidate initializers:
+4 candidate constructors:
   vec2(x: T, y: T) -> vec2<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec2(T) -> vec2<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec2(vec2<T>) -> vec2<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
@@ -1919,9 +1919,9 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: no matching initializer for vec2<f32>(abstract-float, bool)
+              R"(12:34 error: no matching constructor for vec2<f32>(abstract-float, bool)
 
-4 candidate initializers:
+4 candidate constructors:
   vec2(x: T, y: T) -> vec2<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec2(T) -> vec2<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec2(vec2<T>) -> vec2<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
@@ -1958,7 +1958,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: type in struct initializer does not match struct member type: "
+              "12:34 error: type in structure constructor does not match struct member type: "
               "expected 'f32', found 'bool'");
 }
 
@@ -1977,7 +1977,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: type in struct initializer does not match struct member type: "
+              "12:34 error: type in structure constructor does not match struct member type: "
               "expected 'f32', found 'bool'");
 }
 
diff --git a/src/tint/resolver/const_eval_indexing_test.cc b/src/tint/resolver/const_eval_indexing_test.cc
index cfd7aa1..4d8c8cb 100644
--- a/src/tint/resolver/const_eval_indexing_test.cc
+++ b/src/tint/resolver/const_eval_indexing_test.cc
@@ -279,7 +279,7 @@
 
 TEST_F(ResolverConstEvalTest, RuntimeArray_vec3_f32_Index_OOB_Low) {
     auto* sb = GlobalVar("sb", ty.array(ty.vec3<f32>()), Group(0_a), Binding(0_a),
-                         type::AddressSpace::kStorage);
+                         builtin::AddressSpace::kStorage);
     auto* expr = IndexAccessor(sb, Expr(Source{{12, 34}}, -2_i));
     WrapInFunction(expr);
 
diff --git a/src/tint/resolver/init_conv_intrinsic.cc b/src/tint/resolver/ctor_conv_intrinsic.cc
similarity index 63%
rename from src/tint/resolver/init_conv_intrinsic.cc
rename to src/tint/resolver/ctor_conv_intrinsic.cc
index f9f40bf..3ac3a67 100644
--- a/src/tint/resolver/init_conv_intrinsic.cc
+++ b/src/tint/resolver/ctor_conv_intrinsic.cc
@@ -15,52 +15,52 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/resolver/init_conv_intrinsic.cc.tmpl
+//   src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/resolver/init_conv_intrinsic.h"
+#include "src/tint/resolver/ctor_conv_intrinsic.h"
 
 namespace tint::resolver {
 
-const char* str(InitConvIntrinsic i) {
+const char* str(CtorConvIntrinsic i) {
     switch (i) {
-        case InitConvIntrinsic::kNone:
+        case CtorConvIntrinsic::kNone:
             return "<none>";
-        case InitConvIntrinsic::kI32:
+        case CtorConvIntrinsic::kI32:
             return "i32";
-        case InitConvIntrinsic::kU32:
+        case CtorConvIntrinsic::kU32:
             return "u32";
-        case InitConvIntrinsic::kF32:
+        case CtorConvIntrinsic::kF32:
             return "f32";
-        case InitConvIntrinsic::kF16:
+        case CtorConvIntrinsic::kF16:
             return "f16";
-        case InitConvIntrinsic::kBool:
+        case CtorConvIntrinsic::kBool:
             return "bool";
-        case InitConvIntrinsic::kVec2:
+        case CtorConvIntrinsic::kVec2:
             return "vec2";
-        case InitConvIntrinsic::kVec3:
+        case CtorConvIntrinsic::kVec3:
             return "vec3";
-        case InitConvIntrinsic::kVec4:
+        case CtorConvIntrinsic::kVec4:
             return "vec4";
-        case InitConvIntrinsic::kMat2x2:
+        case CtorConvIntrinsic::kMat2x2:
             return "mat2x2";
-        case InitConvIntrinsic::kMat2x3:
+        case CtorConvIntrinsic::kMat2x3:
             return "mat2x3";
-        case InitConvIntrinsic::kMat2x4:
+        case CtorConvIntrinsic::kMat2x4:
             return "mat2x4";
-        case InitConvIntrinsic::kMat3x2:
+        case CtorConvIntrinsic::kMat3x2:
             return "mat3x2";
-        case InitConvIntrinsic::kMat3x3:
+        case CtorConvIntrinsic::kMat3x3:
             return "mat3x3";
-        case InitConvIntrinsic::kMat3x4:
+        case CtorConvIntrinsic::kMat3x4:
             return "mat3x4";
-        case InitConvIntrinsic::kMat4x2:
+        case CtorConvIntrinsic::kMat4x2:
             return "mat4x2";
-        case InitConvIntrinsic::kMat4x3:
+        case CtorConvIntrinsic::kMat4x3:
             return "mat4x3";
-        case InitConvIntrinsic::kMat4x4:
+        case CtorConvIntrinsic::kMat4x4:
             return "mat4x4";
     }
     return "<unknown>";
diff --git a/src/tint/resolver/init_conv_intrinsic.cc.tmpl b/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
similarity index 66%
rename from src/tint/resolver/init_conv_intrinsic.cc.tmpl
rename to src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
index 199cb61..00ac21b 100644
--- a/src/tint/resolver/init_conv_intrinsic.cc.tmpl
+++ b/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
@@ -1,6 +1,6 @@
 {{- /*
 --------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate init_conv_intrinsic.cc
+Template file for use with tools/src/cmd/gen to generate ctor_conv_intrinsic.cc
 
 To update the generated file, run:
     ./tools/run gen
@@ -11,16 +11,16 @@
 --------------------------------------------------------------------------------
 */ -}}
 
-#include "src/tint/resolver/init_conv_intrinsic.h"
+#include "src/tint/resolver/ctor_conv_intrinsic.h"
 
 namespace tint::resolver {
 
-const char* str(InitConvIntrinsic i) {
+const char* str(CtorConvIntrinsic i) {
     switch (i) {
-        case InitConvIntrinsic::kNone:
+        case CtorConvIntrinsic::kNone:
             return "<none>";
-{{- range Sem.InitializersAndConverters  }}
-        case InitConvIntrinsic::k{{Title .Name}}:
+{{- range Sem.ConstructorsAndConverters  }}
+        case CtorConvIntrinsic::k{{Title .Name}}:
             return "{{.Name}}";
 {{- end  }}
     }
diff --git a/src/tint/resolver/ctor_conv_intrinsic.h b/src/tint/resolver/ctor_conv_intrinsic.h
new file mode 100644
index 0000000..4ee1c79
--- /dev/null
+++ b/src/tint/resolver/ctor_conv_intrinsic.h
@@ -0,0 +1,99 @@
+// Copyright 2021 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/resolver/ctor_conv_intrinsic.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_RESOLVER_CTOR_CONV_INTRINSIC_H_
+#define SRC_TINT_RESOLVER_CTOR_CONV_INTRINSIC_H_
+
+#include <cstdint>
+
+namespace tint::resolver {
+
+/// CtorConvIntrinsic is an enumerator of types that have a constructor or converter overload
+/// declared in the intrinsic table.
+enum class CtorConvIntrinsic {
+    kNone = -1,
+    kI32,
+    kU32,
+    kF32,
+    kF16,
+    kBool,
+    kVec2,
+    kVec3,
+    kVec4,
+    kMat2x2,
+    kMat2x3,
+    kMat2x4,
+    kMat3x2,
+    kMat3x3,
+    kMat3x4,
+    kMat4x2,
+    kMat4x3,
+    kMat4x4,
+};
+
+/// @returns the name of the type.
+const char* str(CtorConvIntrinsic i);
+
+/// @param n the width of the vector
+/// @return the CtorConvIntrinsic for a vector of width `n`
+inline CtorConvIntrinsic VectorCtorConvIntrinsic(uint32_t n) {
+    switch (n) {
+        case 2:
+            return CtorConvIntrinsic::kVec2;
+        case 3:
+            return CtorConvIntrinsic::kVec3;
+        case 4:
+            return CtorConvIntrinsic::kVec4;
+    }
+    return CtorConvIntrinsic::kNone;
+}
+
+/// @param c the number of columns in the matrix
+/// @param r the number of rows in the matrix
+/// @return the CtorConvIntrinsic for a matrix with `c` columns and `r` rows
+inline CtorConvIntrinsic MatrixCtorConvIntrinsic(uint32_t c, uint32_t r) {
+    switch ((c - 2) * 3 + (r - 2)) {
+        case 0:
+            return CtorConvIntrinsic::kMat2x2;
+        case 1:
+            return CtorConvIntrinsic::kMat2x3;
+        case 2:
+            return CtorConvIntrinsic::kMat2x4;
+        case 3:
+            return CtorConvIntrinsic::kMat3x2;
+        case 4:
+            return CtorConvIntrinsic::kMat3x3;
+        case 5:
+            return CtorConvIntrinsic::kMat3x4;
+        case 6:
+            return CtorConvIntrinsic::kMat4x2;
+        case 7:
+            return CtorConvIntrinsic::kMat4x3;
+        case 8:
+            return CtorConvIntrinsic::kMat4x4;
+    }
+    return CtorConvIntrinsic::kNone;
+}
+
+}  // namespace tint::resolver
+
+#endif  // SRC_TINT_RESOLVER_CTOR_CONV_INTRINSIC_H_
diff --git a/src/tint/resolver/ctor_conv_intrinsic.h.tmpl b/src/tint/resolver/ctor_conv_intrinsic.h.tmpl
new file mode 100644
index 0000000..349f939
--- /dev/null
+++ b/src/tint/resolver/ctor_conv_intrinsic.h.tmpl
@@ -0,0 +1,76 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate ctor_conv_intrinsic.h
+
+To update the generated file, run:
+    ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+#ifndef SRC_TINT_RESOLVER_CTOR_CONV_INTRINSIC_H_
+#define SRC_TINT_RESOLVER_CTOR_CONV_INTRINSIC_H_
+
+#include <cstdint>
+
+namespace tint::resolver {
+
+/// CtorConvIntrinsic is an enumerator of types that have a constructor or converter overload
+/// declared in the intrinsic table.
+enum class CtorConvIntrinsic {
+    kNone = -1,
+{{- range Sem.ConstructorsAndConverters }}
+    k{{Title .Name}},
+{{- end }}
+};
+
+/// @returns the name of the type.
+const char* str(CtorConvIntrinsic i);
+
+/// @param n the width of the vector
+/// @return the CtorConvIntrinsic for a vector of width `n`
+inline CtorConvIntrinsic VectorCtorConvIntrinsic(uint32_t n) {
+    switch (n) {
+        case 2:
+            return CtorConvIntrinsic::kVec2;
+        case 3:
+            return CtorConvIntrinsic::kVec3;
+        case 4:
+            return CtorConvIntrinsic::kVec4;
+    }
+    return CtorConvIntrinsic::kNone;
+}
+
+/// @param c the number of columns in the matrix
+/// @param r the number of rows in the matrix
+/// @return the CtorConvIntrinsic for a matrix with `c` columns and `r` rows
+inline CtorConvIntrinsic MatrixCtorConvIntrinsic(uint32_t c, uint32_t r) {
+    switch ((c - 2) * 3 + (r - 2)) {
+        case 0:
+            return CtorConvIntrinsic::kMat2x2;
+        case 1:
+            return CtorConvIntrinsic::kMat2x3;
+        case 2:
+            return CtorConvIntrinsic::kMat2x4;
+        case 3:
+            return CtorConvIntrinsic::kMat3x2;
+        case 4:
+            return CtorConvIntrinsic::kMat3x3;
+        case 5:
+            return CtorConvIntrinsic::kMat3x4;
+        case 6:
+            return CtorConvIntrinsic::kMat4x2;
+        case 7:
+            return CtorConvIntrinsic::kMat4x3;
+        case 8:
+            return CtorConvIntrinsic::kMat4x4;
+    }
+    return CtorConvIntrinsic::kNone;
+}
+
+}  // namespace tint::resolver
+
+#endif  // SRC_TINT_RESOLVER_CTOR_CONV_INTRINSIC_H_
diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc
index 16a3f8e..0b8f728 100644
--- a/src/tint/resolver/dependency_graph.cc
+++ b/src/tint/resolver/dependency_graph.cc
@@ -39,6 +39,7 @@
 #include "src/tint/ast/invariant_attribute.h"
 #include "src/tint/ast/location_attribute.h"
 #include "src/tint/ast/loop_statement.h"
+#include "src/tint/ast/must_use_attribute.h"
 #include "src/tint/ast/override.h"
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/stage_attribute.h"
@@ -54,10 +55,11 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/ast/while_statement.h"
 #include "src/tint/ast/workgroup_attribute.h"
+#include "src/tint/builtin/builtin.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/scope_stack.h"
 #include "src/tint/sem/builtin.h"
 #include "src/tint/symbol_table.h"
-#include "src/tint/type/builtin.h"
 #include "src/tint/utils/block_allocator.h"
 #include "src/tint/utils/compiler_macros.h"
 #include "src/tint/utils/defer.h"
@@ -77,8 +79,6 @@
 struct DependencyInfo {
     /// The source of the symbol that forms the dependency
     Source source;
-    /// A string describing how the dependency is referenced. e.g. 'calls'
-    const char* action = nullptr;
 };
 
 /// DependencyEdge describes the two Globals used to define a dependency
@@ -172,24 +172,20 @@
                 Declare(str->name->symbol, str);
                 for (auto* member : str->members) {
                     TraverseAttributes(member->attributes);
-                    TraverseTypeExpression(member->type);
+                    TraverseExpression(member->type);
                 }
             },
             [&](const ast::Alias* alias) {
                 Declare(alias->name->symbol, alias);
-                TraverseTypeExpression(alias->type);
+                TraverseExpression(alias->type);
             },
             [&](const ast::Function* func) {
                 Declare(func->name->symbol, func);
                 TraverseFunction(func);
             },
-            [&](const ast::Variable* var) {
-                Declare(var->name->symbol, var);
-                TraverseTypeExpression(var->type);
-                TraverseAttributes(var->attributes);
-                if (var->initializer) {
-                    TraverseValueExpression(var->initializer);
-                }
+            [&](const ast::Variable* v) {
+                Declare(v->name->symbol, v);
+                TraverseVariable(v);
             },
             [&](const ast::DiagnosticDirective*) {
                 // Diagnostic directives do not affect the dependency graph.
@@ -197,15 +193,23 @@
             [&](const ast::Enable*) {
                 // Enable directives do not affect the dependency graph.
             },
-            [&](const ast::ConstAssert* assertion) {
-                TraverseValueExpression(assertion->condition);
-            },
+            [&](const ast::ConstAssert* assertion) { TraverseExpression(assertion->condition); },
             [&](Default) { UnhandledNode(diagnostics_, global->node); });
     }
 
   private:
-    /// Traverses the function, performing symbol resolution and determining
-    /// global dependencies.
+    /// Traverses the variable, performing symbol resolution.
+    void TraverseVariable(const ast::Variable* v) {
+        if (auto* var = v->As<ast::Var>()) {
+            TraverseExpression(var->declared_address_space);
+            TraverseExpression(var->declared_access);
+        }
+        TraverseExpression(v->type);
+        TraverseAttributes(v->attributes);
+        TraverseExpression(v->initializer);
+    }
+
+    /// Traverses the function, performing symbol resolution and determining global dependencies.
     void TraverseFunction(const ast::Function* func) {
         TraverseAttributes(func->attributes);
         TraverseAttributes(func->return_type_attributes);
@@ -214,10 +218,10 @@
         // with the same identifier as its type.
         for (auto* param : func->params) {
             TraverseAttributes(param->attributes);
-            TraverseTypeExpression(param->type);
+            TraverseExpression(param->type);
         }
         // Resolve the return type
-        TraverseTypeExpression(func->return_type);
+        TraverseExpression(func->return_type);
 
         // Push the scope stack for the parameters and function body.
         scope_stack_.Push();
@@ -251,29 +255,29 @@
         Switch(
             stmt,  //
             [&](const ast::AssignmentStatement* a) {
-                TraverseValueExpression(a->lhs);
-                TraverseValueExpression(a->rhs);
+                TraverseExpression(a->lhs);
+                TraverseExpression(a->rhs);
             },
             [&](const ast::BlockStatement* b) {
                 scope_stack_.Push();
                 TINT_DEFER(scope_stack_.Pop());
                 TraverseStatements(b->statements);
             },
-            [&](const ast::BreakIfStatement* b) { TraverseValueExpression(b->condition); },
-            [&](const ast::CallStatement* r) { TraverseValueExpression(r->expr); },
+            [&](const ast::BreakIfStatement* b) { TraverseExpression(b->condition); },
+            [&](const ast::CallStatement* r) { TraverseExpression(r->expr); },
             [&](const ast::CompoundAssignmentStatement* a) {
-                TraverseValueExpression(a->lhs);
-                TraverseValueExpression(a->rhs);
+                TraverseExpression(a->lhs);
+                TraverseExpression(a->rhs);
             },
             [&](const ast::ForLoopStatement* l) {
                 scope_stack_.Push();
                 TINT_DEFER(scope_stack_.Pop());
                 TraverseStatement(l->initializer);
-                TraverseValueExpression(l->condition);
+                TraverseExpression(l->condition);
                 TraverseStatement(l->continuing);
                 TraverseStatement(l->body);
             },
-            [&](const ast::IncrementDecrementStatement* i) { TraverseValueExpression(i->lhs); },
+            [&](const ast::IncrementDecrementStatement* i) { TraverseExpression(i->lhs); },
             [&](const ast::LoopStatement* l) {
                 scope_stack_.Push();
                 TINT_DEFER(scope_stack_.Pop());
@@ -281,18 +285,18 @@
                 TraverseStatement(l->continuing);
             },
             [&](const ast::IfStatement* i) {
-                TraverseValueExpression(i->condition);
+                TraverseExpression(i->condition);
                 TraverseStatement(i->body);
                 if (i->else_statement) {
                     TraverseStatement(i->else_statement);
                 }
             },
-            [&](const ast::ReturnStatement* r) { TraverseValueExpression(r->value); },
+            [&](const ast::ReturnStatement* r) { TraverseExpression(r->value); },
             [&](const ast::SwitchStatement* s) {
-                TraverseValueExpression(s->condition);
+                TraverseExpression(s->condition);
                 for (auto* c : s->body) {
                     for (auto* sel : c->selectors) {
-                        TraverseValueExpression(sel->expr);
+                        TraverseExpression(sel->expr);
                     }
                     TraverseStatement(c->body);
                 }
@@ -301,19 +305,16 @@
                 if (auto* shadows = scope_stack_.Get(v->variable->name->symbol)) {
                     graph_.shadows.Add(v->variable, shadows);
                 }
-                TraverseTypeExpression(v->variable->type);
-                TraverseValueExpression(v->variable->initializer);
+                TraverseVariable(v->variable);
                 Declare(v->variable->name->symbol, v->variable);
             },
             [&](const ast::WhileStatement* w) {
                 scope_stack_.Push();
                 TINT_DEFER(scope_stack_.Pop());
-                TraverseValueExpression(w->condition);
+                TraverseExpression(w->condition);
                 TraverseStatement(w->body);
             },
-            [&](const ast::ConstAssert* assertion) {
-                TraverseValueExpression(assertion->condition);
-            },
+            [&](const ast::ConstAssert* assertion) { TraverseExpression(assertion->condition); },
             [&](Default) {
                 if (TINT_UNLIKELY((!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
                                                   ast::DiscardStatement>()))) {
@@ -333,58 +334,28 @@
         }
     }
 
-    /// Traverses the expression @p root_expr for the intended use as a value, performing symbol
-    /// resolution and determining global dependencies.
-    void TraverseValueExpression(const ast::Expression* root) {
-        TraverseExpression(root, "identifier", "references");
-    }
-
-    /// Traverses the expression @p root_expr for the intended use as a type, performing symbol
-    /// resolution and determining global dependencies.
-    void TraverseTypeExpression(const ast::Expression* root) {
-        TraverseExpression(root, "type", "references");
-    }
-
-    /// Traverses the expression @p root_expr for the intended use as a call target, performing
-    /// symbol resolution and determining global dependencies.
-    void TraverseCallableExpression(const ast::Expression* root) {
-        TraverseExpression(root, "function", "calls");
-    }
-
     /// Traverses the expression @p root_expr, performing symbol resolution and determining global
     /// dependencies.
-    void TraverseExpression(const ast::Expression* root_expr,
-                            const char* root_use,
-                            const char* root_action) {
+    void TraverseExpression(const ast::Expression* root_expr) {
         if (!root_expr) {
             return;
         }
 
-        struct Pending {
-            const ast::Expression* expr;
-            const char* use;
-            const char* action;
-        };
-        utils::Vector<Pending, 8> pending{{root_expr, root_use, root_action}};
+        utils::Vector<const ast::Expression*, 8> pending{root_expr};
         while (!pending.IsEmpty()) {
-            auto next = pending.Pop();
-            ast::TraverseExpressions(next.expr, diagnostics_, [&](const ast::Expression* expr) {
+            ast::TraverseExpressions(pending.Pop(), diagnostics_, [&](const ast::Expression* expr) {
                 Switch(
                     expr,
                     [&](const ast::IdentifierExpression* e) {
-                        AddDependency(e->identifier, e->identifier->symbol, next.use, next.action);
+                        AddDependency(e->identifier, e->identifier->symbol);
                         if (auto* tmpl_ident = e->identifier->As<ast::TemplatedIdentifier>()) {
                             for (auto* arg : tmpl_ident->arguments) {
-                                pending.Push({arg, "identifier", "references"});
+                                pending.Push(arg);
                             }
                         }
                     },
-                    [&](const ast::CallExpression* call) {
-                        TraverseCallableExpression(call->target);
-                    },
-                    [&](const ast::BitcastExpression* cast) {
-                        TraverseTypeExpression(cast->type);
-                    });
+                    [&](const ast::CallExpression* call) { TraverseExpression(call->target); },
+                    [&](const ast::BitcastExpression* cast) { TraverseExpression(cast->type); });
                 return ast::TraverseAction::Descend;
             });
         }
@@ -404,33 +375,42 @@
         bool handled = Switch(
             attr,
             [&](const ast::BindingAttribute* binding) {
-                TraverseValueExpression(binding->expr);
+                TraverseExpression(binding->expr);
+                return true;
+            },
+            [&](const ast::BuiltinAttribute* builtin) {
+                TraverseExpression(builtin->builtin);
                 return true;
             },
             [&](const ast::GroupAttribute* group) {
-                TraverseValueExpression(group->expr);
+                TraverseExpression(group->expr);
                 return true;
             },
             [&](const ast::IdAttribute* id) {
-                TraverseValueExpression(id->expr);
+                TraverseExpression(id->expr);
+                return true;
+            },
+            [&](const ast::InterpolateAttribute* interpolate) {
+                TraverseExpression(interpolate->type);
+                TraverseExpression(interpolate->sampling);
                 return true;
             },
             [&](const ast::LocationAttribute* loc) {
-                TraverseValueExpression(loc->expr);
+                TraverseExpression(loc->expr);
                 return true;
             },
             [&](const ast::StructMemberAlignAttribute* align) {
-                TraverseValueExpression(align->expr);
+                TraverseExpression(align->expr);
                 return true;
             },
             [&](const ast::StructMemberSizeAttribute* size) {
-                TraverseValueExpression(size->expr);
+                TraverseExpression(size->expr);
                 return true;
             },
             [&](const ast::WorkgroupAttribute* wg) {
-                TraverseValueExpression(wg->x);
-                TraverseValueExpression(wg->y);
-                TraverseValueExpression(wg->z);
+                TraverseExpression(wg->x);
+                TraverseExpression(wg->y);
+                TraverseExpression(wg->z);
                 return true;
             });
         if (handled) {
@@ -438,8 +418,9 @@
         }
 
         if (attr->IsAnyOf<ast::BuiltinAttribute, ast::DiagnosticAttribute, ast::InternalAttribute,
-                          ast::InterpolateAttribute, ast::InvariantAttribute, ast::StageAttribute,
-                          ast::StrideAttribute, ast::StructMemberOffsetAttribute>()) {
+                          ast::InterpolateAttribute, ast::InvariantAttribute, ast::MustUseAttribute,
+                          ast::StageAttribute, ast::StrideAttribute,
+                          ast::StructMemberOffsetAttribute>()) {
             return;
         }
 
@@ -447,10 +428,7 @@
     }
 
     /// Adds the dependency from @p from to @p to, erroring if @p to cannot be resolved.
-    void AddDependency(const ast::Identifier* from,
-                       Symbol to,
-                       const char* use,
-                       const char* action) {
+    void AddDependency(const ast::Identifier* from, Symbol to) {
         auto* resolved = scope_stack_.Get(to);
         if (!resolved) {
             auto s = symbols_.NameFor(to);
@@ -458,30 +436,48 @@
                 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_fn));
                 return;
             }
-            if (auto builtin_ty = type::ParseBuiltin(s); builtin_ty != type::Builtin::kUndefined) {
+            if (auto builtin_ty = builtin::ParseBuiltin(s);
+                builtin_ty != builtin::Builtin::kUndefined) {
                 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_ty));
                 return;
             }
-            if (auto addr = type::ParseAddressSpace(s); addr != type::AddressSpace::kUndefined) {
+            if (auto builtin_val = builtin::ParseBuiltinValue(s);
+                builtin_val != builtin::BuiltinValue::kUndefined) {
+                graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_val));
+                return;
+            }
+            if (auto addr = builtin::ParseAddressSpace(s);
+                addr != builtin::AddressSpace::kUndefined) {
                 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(addr));
                 return;
             }
-            if (auto fmt = type::ParseTexelFormat(s); fmt != type::TexelFormat::kUndefined) {
+            if (auto fmt = builtin::ParseTexelFormat(s); fmt != builtin::TexelFormat::kUndefined) {
                 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(fmt));
                 return;
             }
-            if (auto access = type::ParseAccess(s); access != type::Access::kUndefined) {
+            if (auto access = builtin::ParseAccess(s); access != builtin::Access::kUndefined) {
                 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(access));
                 return;
             }
+            if (auto i_type = builtin::ParseInterpolationType(s);
+                i_type != builtin::InterpolationType::kUndefined) {
+                graph_.resolved_identifiers.Add(from, ResolvedIdentifier(i_type));
+                return;
+            }
+            if (auto i_smpl = builtin::ParseInterpolationSampling(s);
+                i_smpl != builtin::InterpolationSampling::kUndefined) {
+                graph_.resolved_identifiers.Add(from, ResolvedIdentifier(i_smpl));
+                return;
+            }
 
-            UnknownSymbol(to, from->source, use);
+            // Unresolved.
+            graph_.resolved_identifiers.Add(from, UnresolvedIdentifier{s});
             return;
         }
 
         if (auto global = globals_.Find(to); global && (*global)->node == resolved) {
             if (dependency_edges_.Add(DependencyEdge{current_global_, *global},
-                                      DependencyInfo{from->source, action})) {
+                                      DependencyInfo{from->source})) {
                 current_global_->deps.Push(*global);
             }
         }
@@ -489,12 +485,6 @@
         graph_.resolved_identifiers.Add(from, ResolvedIdentifier(resolved));
     }
 
-    /// Appends an error to the diagnostics that the given symbol cannot be resolved.
-    void UnknownSymbol(Symbol name, Source source, const char* use) {
-        AddError(diagnostics_, "unknown " + std::string(use) + ": '" + symbols_.NameFor(name) + "'",
-                 source);
-    }
-
     using VariableMap = utils::Hashmap<Symbol, const ast::Variable*, 32>;
     const SymbolTable& symbols_;
     const GlobalMap& globals_;
@@ -741,7 +731,7 @@
             auto* to = (i + 1 < stack.Length()) ? stack[i + 1] : stack[loop_start];
             auto info = DepInfoFor(from, to);
             AddNote(diagnostics_,
-                    KindOf(from->node) + " '" + NameOf(from->node) + "' " + info.action + " " +
+                    KindOf(from->node) + " '" + NameOf(from->node) + "' references " +
                         KindOf(to->node) + " '" + NameOf(to->node) + "' here",
                     info.source);
         }
@@ -785,8 +775,7 @@
     /// Global map, keyed by name. Populated by GatherGlobals().
     GlobalMap globals_;
 
-    /// Map of DependencyEdge to DependencyInfo. Populated by
-    /// DetermineDependencies().
+    /// Map of DependencyEdge to DependencyInfo. Populated by DetermineDependencies().
     DependencyEdges dependency_edges_;
 
     /// Globals in declaration order. Populated by GatherGlobals().
@@ -811,9 +800,6 @@
 }
 
 std::string ResolvedIdentifier::String(const SymbolTable& symbols, diag::List& diagnostics) const {
-    if (!Resolved()) {
-        return "<unresolved symbol>";
-    }
     if (auto* node = Node()) {
         return Switch(
             node,
@@ -832,6 +818,9 @@
             [&](const ast::Function* n) {  //
                 return "function '" + symbols.NameFor(n->name->symbol) + "'";
             },
+            [&](const ast::Parameter* n) {  //
+                return "parameter '" + symbols.NameFor(n->name->symbol) + "'";
+            },
             [&](Default) {
                 TINT_UNREACHABLE(Resolver, diagnostics)
                     << "unhandled ast::Node: " << node->TypeInfo().name;
@@ -841,18 +830,31 @@
     if (auto builtin_fn = BuiltinFunction(); builtin_fn != sem::BuiltinType::kNone) {
         return "builtin function '" + utils::ToString(builtin_fn) + "'";
     }
-    if (auto builtin_ty = BuiltinType(); builtin_ty != type::Builtin::kUndefined) {
+    if (auto builtin_ty = BuiltinType(); builtin_ty != builtin::Builtin::kUndefined) {
         return "builtin type '" + utils::ToString(builtin_ty) + "'";
     }
-    if (auto access = Access(); access != type::Access::kUndefined) {
+    if (auto builtin_val = BuiltinValue(); builtin_val != builtin::BuiltinValue::kUndefined) {
+        return "builtin value '" + utils::ToString(builtin_val) + "'";
+    }
+    if (auto access = Access(); access != builtin::Access::kUndefined) {
         return "access '" + utils::ToString(access) + "'";
     }
-    if (auto addr = AddressSpace(); addr != type::AddressSpace::kUndefined) {
+    if (auto addr = AddressSpace(); addr != builtin::AddressSpace::kUndefined) {
         return "address space '" + utils::ToString(addr) + "'";
     }
-    if (auto fmt = TexelFormat(); fmt != type::TexelFormat::kUndefined) {
+    if (auto type = InterpolationType(); type != builtin::InterpolationType::kUndefined) {
+        return "interpolation type '" + utils::ToString(type) + "'";
+    }
+    if (auto smpl = InterpolationSampling(); smpl != builtin::InterpolationSampling::kUndefined) {
+        return "interpolation sampling '" + utils::ToString(smpl) + "'";
+    }
+    if (auto fmt = TexelFormat(); fmt != builtin::TexelFormat::kUndefined) {
         return "texel format '" + utils::ToString(fmt) + "'";
     }
+    if (auto* unresolved = Unresolved()) {
+        return "unresolved identifier '" + unresolved->name + "'";
+    }
+
     TINT_UNREACHABLE(Resolver, diagnostics) << "unhandled ResolvedIdentifier";
     return "<unknown>";
 }
diff --git a/src/tint/resolver/dependency_graph.h b/src/tint/resolver/dependency_graph.h
index 7819b52..429a47a 100644
--- a/src/tint/resolver/dependency_graph.h
+++ b/src/tint/resolver/dependency_graph.h
@@ -19,37 +19,53 @@
 #include <vector>
 
 #include "src/tint/ast/module.h"
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/builtin.h"
+#include "src/tint/builtin/builtin_value.h"
+#include "src/tint/builtin/interpolation_sampling.h"
+#include "src/tint/builtin/interpolation_type.h"
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/diagnostic/diagnostic.h"
 #include "src/tint/sem/builtin_type.h"
 #include "src/tint/symbol_table.h"
-#include "src/tint/type/access.h"
-#include "src/tint/type/builtin.h"
-#include "src/tint/type/texel_format.h"
 #include "src/tint/utils/hashmap.h"
 
 namespace tint::resolver {
 
+/// UnresolvedIdentifier is the variant value used by ResolvedIdentifier
+struct UnresolvedIdentifier {
+    /// Name of the unresolved identifier
+    std::string name;
+};
+
 /// ResolvedIdentifier holds the resolution of an ast::Identifier.
 /// Can hold one of:
+/// - UnresolvedIdentifier
 /// - const ast::TypeDecl*  (as const ast::Node*)
 /// - const ast::Variable*  (as const ast::Node*)
 /// - const ast::Function*  (as const ast::Node*)
 /// - sem::BuiltinType
-/// - type::Access
-/// - type::AddressSpace
-/// - type::Builtin
-/// - type::TexelFormat
+/// - builtin::Access
+/// - builtin::AddressSpace
+/// - builtin::Builtin
+/// - builtin::BuiltinValue
+/// - builtin::InterpolationSampling
+/// - builtin::InterpolationType
+/// - builtin::TexelFormat
 class ResolvedIdentifier {
   public:
-    ResolvedIdentifier() = default;
-
     /// Constructor
     /// @param value the resolved identifier value
     template <typename T>
     ResolvedIdentifier(T value) : value_(value) {}  // NOLINT(runtime/explicit)
 
-    /// @return true if the ResolvedIdentifier holds a value (successfully resolved)
-    bool Resolved() const { return !std::holds_alternative<std::monostate>(value_); }
+    /// @return the UnresolvedIdentifier if the identifier was not resolved
+    const UnresolvedIdentifier* Unresolved() const {
+        if (auto n = std::get_if<UnresolvedIdentifier>(&value_)) {
+            return n;
+        }
+        return nullptr;
+    }
 
     /// @return the node pointer if the ResolvedIdentifier holds an AST node, otherwise nullptr
     const ast::Node* Node() const {
@@ -68,40 +84,67 @@
         return sem::BuiltinType::kNone;
     }
 
-    /// @return the access if the ResolvedIdentifier holds type::Access, otherwise
-    /// type::Access::kUndefined
-    type::Access Access() const {
-        if (auto n = std::get_if<type::Access>(&value_)) {
+    /// @return the access if the ResolvedIdentifier holds builtin::Access, otherwise
+    /// builtin::Access::kUndefined
+    builtin::Access Access() const {
+        if (auto n = std::get_if<builtin::Access>(&value_)) {
             return *n;
         }
-        return type::Access::kUndefined;
+        return builtin::Access::kUndefined;
     }
 
-    /// @return the address space if the ResolvedIdentifier holds type::AddressSpace, otherwise
-    /// type::AddressSpace::kUndefined
-    type::AddressSpace AddressSpace() const {
-        if (auto n = std::get_if<type::AddressSpace>(&value_)) {
+    /// @return the address space if the ResolvedIdentifier holds builtin::AddressSpace, otherwise
+    /// builtin::AddressSpace::kUndefined
+    builtin::AddressSpace AddressSpace() const {
+        if (auto n = std::get_if<builtin::AddressSpace>(&value_)) {
             return *n;
         }
-        return type::AddressSpace::kUndefined;
+        return builtin::AddressSpace::kUndefined;
     }
 
-    /// @return the builtin type if the ResolvedIdentifier holds type::Builtin, otherwise
-    /// type::Builtin::kUndefined
-    type::Builtin BuiltinType() const {
-        if (auto n = std::get_if<type::Builtin>(&value_)) {
+    /// @return the builtin type if the ResolvedIdentifier holds builtin::Builtin, otherwise
+    /// builtin::Builtin::kUndefined
+    builtin::Builtin BuiltinType() const {
+        if (auto n = std::get_if<builtin::Builtin>(&value_)) {
             return *n;
         }
-        return type::Builtin::kUndefined;
+        return builtin::Builtin::kUndefined;
+    }
+
+    /// @return the builtin value if the ResolvedIdentifier holds builtin::BuiltinValue, otherwise
+    /// builtin::BuiltinValue::kUndefined
+    builtin::BuiltinValue BuiltinValue() const {
+        if (auto n = std::get_if<builtin::BuiltinValue>(&value_)) {
+            return *n;
+        }
+        return builtin::BuiltinValue::kUndefined;
+    }
+
+    /// @return the texel format if the ResolvedIdentifier holds type::InterpolationSampling,
+    /// otherwise type::InterpolationSampling::kUndefined
+    builtin::InterpolationSampling InterpolationSampling() const {
+        if (auto n = std::get_if<builtin::InterpolationSampling>(&value_)) {
+            return *n;
+        }
+        return builtin::InterpolationSampling::kUndefined;
+    }
+
+    /// @return the texel format if the ResolvedIdentifier holds type::InterpolationType,
+    /// otherwise type::InterpolationType::kUndefined
+    builtin::InterpolationType InterpolationType() const {
+        if (auto n = std::get_if<builtin::InterpolationType>(&value_)) {
+            return *n;
+        }
+        return builtin::InterpolationType::kUndefined;
     }
 
     /// @return the texel format if the ResolvedIdentifier holds type::TexelFormat, otherwise
     /// type::TexelFormat::kUndefined
-    type::TexelFormat TexelFormat() const {
-        if (auto n = std::get_if<type::TexelFormat>(&value_)) {
+    builtin::TexelFormat TexelFormat() const {
+        if (auto n = std::get_if<builtin::TexelFormat>(&value_)) {
             return *n;
         }
-        return type::TexelFormat::kUndefined;
+        return builtin::TexelFormat::kUndefined;
     }
 
     /// @param value the value to compare the ResolvedIdentifier to
@@ -127,13 +170,16 @@
     std::string String(const SymbolTable& symbols, diag::List& diagnostics) const;
 
   private:
-    std::variant<std::monostate,
+    std::variant<UnresolvedIdentifier,
                  const ast::Node*,
                  sem::BuiltinType,
-                 type::Access,
-                 type::AddressSpace,
-                 type::Builtin,
-                 type::TexelFormat>
+                 builtin::Access,
+                 builtin::AddressSpace,
+                 builtin::Builtin,
+                 builtin::BuiltinValue,
+                 builtin::InterpolationSampling,
+                 builtin::InterpolationType,
+                 builtin::TexelFormat>
         value_;
 };
 
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index 31e484e..c81c336 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -17,9 +17,11 @@
 #include <utility>
 
 #include "gmock/gmock.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/resolver/dependency_graph.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/transform.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -138,6 +140,40 @@
     WorkgroupSizeValue,
 };
 
+static constexpr SymbolUseKind kAllUseKinds[] = {
+    SymbolUseKind::GlobalVarType,
+    SymbolUseKind::GlobalVarArrayElemType,
+    SymbolUseKind::GlobalVarArraySizeValue,
+    SymbolUseKind::GlobalVarVectorElemType,
+    SymbolUseKind::GlobalVarMatrixElemType,
+    SymbolUseKind::GlobalVarSampledTexElemType,
+    SymbolUseKind::GlobalVarMultisampledTexElemType,
+    SymbolUseKind::GlobalVarValue,
+    SymbolUseKind::GlobalConstType,
+    SymbolUseKind::GlobalConstArrayElemType,
+    SymbolUseKind::GlobalConstArraySizeValue,
+    SymbolUseKind::GlobalConstVectorElemType,
+    SymbolUseKind::GlobalConstMatrixElemType,
+    SymbolUseKind::GlobalConstValue,
+    SymbolUseKind::AliasType,
+    SymbolUseKind::StructMemberType,
+    SymbolUseKind::CallFunction,
+    SymbolUseKind::ParameterType,
+    SymbolUseKind::LocalVarType,
+    SymbolUseKind::LocalVarArrayElemType,
+    SymbolUseKind::LocalVarArraySizeValue,
+    SymbolUseKind::LocalVarVectorElemType,
+    SymbolUseKind::LocalVarMatrixElemType,
+    SymbolUseKind::LocalVarValue,
+    SymbolUseKind::LocalLetType,
+    SymbolUseKind::LocalLetValue,
+    SymbolUseKind::NestedLocalVarType,
+    SymbolUseKind::NestedLocalVarValue,
+    SymbolUseKind::NestedLocalLetType,
+    SymbolUseKind::NestedLocalLetValue,
+    SymbolUseKind::WorkgroupSizeValue,
+};
+
 static constexpr SymbolUseKind kTypeUseKinds[] = {
     SymbolUseKind::GlobalVarType,
     SymbolUseKind::GlobalVarArrayElemType,
@@ -273,47 +309,6 @@
     return out << "<unknown>";
 }
 
-/// @returns the the diagnostic message name used for the given use
-std::string DiagString(SymbolUseKind kind) {
-    switch (kind) {
-        case SymbolUseKind::GlobalVarType:
-        case SymbolUseKind::GlobalConstType:
-        case SymbolUseKind::AliasType:
-        case SymbolUseKind::StructMemberType:
-        case SymbolUseKind::ParameterType:
-        case SymbolUseKind::LocalVarType:
-        case SymbolUseKind::LocalLetType:
-        case SymbolUseKind::NestedLocalVarType:
-        case SymbolUseKind::NestedLocalLetType:
-            return "type";
-        case SymbolUseKind::GlobalVarArrayElemType:
-        case SymbolUseKind::GlobalVarVectorElemType:
-        case SymbolUseKind::GlobalVarMatrixElemType:
-        case SymbolUseKind::GlobalVarSampledTexElemType:
-        case SymbolUseKind::GlobalVarMultisampledTexElemType:
-        case SymbolUseKind::GlobalConstArrayElemType:
-        case SymbolUseKind::GlobalConstVectorElemType:
-        case SymbolUseKind::GlobalConstMatrixElemType:
-        case SymbolUseKind::LocalVarArrayElemType:
-        case SymbolUseKind::LocalVarVectorElemType:
-        case SymbolUseKind::LocalVarMatrixElemType:
-        case SymbolUseKind::GlobalVarValue:
-        case SymbolUseKind::GlobalVarArraySizeValue:
-        case SymbolUseKind::GlobalConstValue:
-        case SymbolUseKind::GlobalConstArraySizeValue:
-        case SymbolUseKind::LocalVarValue:
-        case SymbolUseKind::LocalVarArraySizeValue:
-        case SymbolUseKind::LocalLetValue:
-        case SymbolUseKind::NestedLocalVarValue:
-        case SymbolUseKind::NestedLocalLetValue:
-        case SymbolUseKind::WorkgroupSizeValue:
-            return "identifier";
-        case SymbolUseKind::CallFunction:
-            return "function";
-    }
-    return "<unknown>";
-}
-
 /// @returns the declaration scope depth for the symbol declaration kind.
 ///          Globals are at depth 0, parameters and locals are at depth 1,
 ///          nested locals are at depth 2.
@@ -425,7 +420,7 @@
     auto& b = *builder;
     switch (kind) {
         case SymbolDeclKind::GlobalVar:
-            return b.GlobalVar(source, symbol, b.ty.i32(), type::AddressSpace::kPrivate);
+            return b.GlobalVar(source, symbol, b.ty.i32(), builtin::AddressSpace::kPrivate);
         case SymbolDeclKind::GlobalConst:
             return b.GlobalConst(source, symbol, b.ty.i32(), b.Expr(1_i));
         case SymbolDeclKind::Alias:
@@ -470,27 +465,27 @@
     switch (kind) {
         case SymbolUseKind::GlobalVarType: {
             auto node = b.ty(source, symbol);
-            b.GlobalVar(b.Sym(), node, type::AddressSpace::kPrivate);
+            b.GlobalVar(b.Sym(), node, builtin::AddressSpace::kPrivate);
             return node->identifier;
         }
         case SymbolUseKind::GlobalVarArrayElemType: {
             auto node = b.ty(source, symbol);
-            b.GlobalVar(b.Sym(), b.ty.array(node, 4_i), type::AddressSpace::kPrivate);
+            b.GlobalVar(b.Sym(), b.ty.array(node, 4_i), builtin::AddressSpace::kPrivate);
             return node->identifier;
         }
         case SymbolUseKind::GlobalVarArraySizeValue: {
             auto* node = b.Expr(source, symbol);
-            b.GlobalVar(b.Sym(), b.ty.array(b.ty.i32(), node), type::AddressSpace::kPrivate);
+            b.GlobalVar(b.Sym(), b.ty.array(b.ty.i32(), node), builtin::AddressSpace::kPrivate);
             return node->identifier;
         }
         case SymbolUseKind::GlobalVarVectorElemType: {
             auto node = b.ty(source, symbol);
-            b.GlobalVar(b.Sym(), b.ty.vec3(node), type::AddressSpace::kPrivate);
+            b.GlobalVar(b.Sym(), b.ty.vec3(node), builtin::AddressSpace::kPrivate);
             return node->identifier;
         }
         case SymbolUseKind::GlobalVarMatrixElemType: {
             ast::Type node = b.ty(source, symbol);
-            b.GlobalVar(b.Sym(), b.ty.mat3x4(node), type::AddressSpace::kPrivate);
+            b.GlobalVar(b.Sym(), b.ty.mat3x4(node), builtin::AddressSpace::kPrivate);
             return node->identifier;
         }
         case SymbolUseKind::GlobalVarSampledTexElemType: {
@@ -505,7 +500,7 @@
         }
         case SymbolUseKind::GlobalVarValue: {
             auto* node = b.Expr(source, symbol);
-            b.GlobalVar(b.Sym(), b.ty.i32(), type::AddressSpace::kPrivate, node);
+            b.GlobalVar(b.Sym(), b.ty.i32(), builtin::AddressSpace::kPrivate, node);
             return node->identifier;
         }
         case SymbolUseKind::GlobalConstType: {
@@ -726,7 +721,7 @@
              Block(Assign(Expr(Source{{12, 34}}, "G"), 3.14_f)),
          });
 
-    GlobalVar(Source{{56, 78}}, "G", ty.f32(), type::AddressSpace::kPrivate, Expr(2.1_f));
+    GlobalVar(Source{{56, 78}}, "G", ty.f32(), builtin::AddressSpace::kPrivate, Expr(2.1_f));
 
     Build();
 }
@@ -747,10 +742,16 @@
 
     // Build a use of a non-existent symbol
     SymbolTestHelper helper(this);
-    helper.Add(use_kind, symbol, Source{{56, 78}});
+    auto* ident = helper.Add(use_kind, symbol, Source{{56, 78}});
     helper.Build();
 
-    Build("56:78 error: unknown " + DiagString(use_kind) + ": 'SYMBOL'");
+    auto graph = Build();
+
+    auto resolved_identifier = graph.resolved_identifiers.Find(ident);
+    ASSERT_NE(resolved_identifier, nullptr);
+    auto* unresolved = resolved_identifier->Unresolved();
+    ASSERT_NE(unresolved, nullptr);
+    EXPECT_EQ(unresolved->name, "SYMBOL");
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -790,14 +791,28 @@
 
 TEST_F(ResolverDependencyGraphDeclSelfUse, LocalVar) {
     const Symbol symbol = Sym("SYMBOL");
-    WrapInFunction(Decl(Var(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i))));
-    Build("12:34 error: unknown identifier: 'SYMBOL'");
+    auto* ident = Ident(Source{{12, 34}}, symbol);
+    WrapInFunction(Decl(Var(symbol, ty.i32(), Mul(Expr(ident), 123_i))));
+    auto graph = Build();
+
+    auto resolved_identifier = graph.resolved_identifiers.Find(ident);
+    ASSERT_TRUE(resolved_identifier);
+    auto* unresolved = resolved_identifier->Unresolved();
+    ASSERT_NE(unresolved, nullptr);
+    EXPECT_EQ(unresolved->name, "SYMBOL");
 }
 
 TEST_F(ResolverDependencyGraphDeclSelfUse, LocalLet) {
     const Symbol symbol = Sym("SYMBOL");
-    WrapInFunction(Decl(Let(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i))));
-    Build("12:34 error: unknown identifier: 'SYMBOL'");
+    auto* ident = Ident(Source{{12, 34}}, symbol);
+    WrapInFunction(Decl(Let(symbol, ty.i32(), Mul(Expr(ident), 123_i))));
+    auto graph = Build();
+
+    auto resolved_identifier = graph.resolved_identifiers.Find(ident);
+    ASSERT_TRUE(resolved_identifier);
+    auto* unresolved = resolved_identifier->Unresolved();
+    ASSERT_NE(unresolved, nullptr);
+    EXPECT_EQ(unresolved->name, "SYMBOL");
 }
 
 }  // namespace undeclared_tests
@@ -816,7 +831,7 @@
          utils::Vector{CallStmt(Call(Ident(Source{{56, 78}}, "main")))});
 
     Build(R"(12:34 error: cyclic dependency found: 'main' -> 'main'
-56:78 note: function 'main' calls function 'main' here)");
+56:78 note: function 'main' references function 'main' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, IndirectCall) {
@@ -840,9 +855,9 @@
          utils::Vector{CallStmt(Call(Ident(Source{{5, 10}}, "c")))});
 
     Build(R"(5:1 error: cyclic dependency found: 'b' -> 'c' -> 'd' -> 'b'
-5:10 note: function 'b' calls function 'c' here
-4:10 note: function 'c' calls function 'd' here
-3:10 note: function 'd' calls function 'b' here)");
+5:10 note: function 'b' references function 'c' here
+4:10 note: function 'c' references function 'd' here
+3:10 note: function 'd' references function 'b' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, Alias_Direct) {
@@ -1096,7 +1111,7 @@
     auto* var_1 = GlobalVar("SYMBOL1", ty.i32());
     auto* enable = Enable(builtin::Extension::kF16);
     auto* var_2 = GlobalVar("SYMBOL2", ty.f32());
-    auto* diagnostic = DiagnosticDirective(ast::DiagnosticSeverity::kWarning, "foo");
+    auto* diagnostic = DiagnosticDirective(builtin::DiagnosticSeverity::kWarning, "foo");
 
     EXPECT_THAT(AST().GlobalDeclarations(), ElementsAre(var_1, enable, var_2, diagnostic));
     EXPECT_THAT(Build().ordered_globals, ElementsAre(enable, diagnostic, var_1, var_2));
@@ -1124,17 +1139,22 @@
 
     // If the declaration is visible to the use, then we expect the analysis to
     // succeed.
-    bool expect_pass = ScopeDepth(decl_kind) <= ScopeDepth(use_kind);
-    auto graph = Build(expect_pass ? "" : "56:78 error: unknown identifier: 'SYMBOL'");
+    bool expect_resolved = ScopeDepth(decl_kind) <= ScopeDepth(use_kind);
+    auto graph = Build();
 
-    if (expect_pass) {
+    auto resolved_identifier = graph.resolved_identifiers.Find(use);
+    ASSERT_TRUE(resolved_identifier);
+
+    if (expect_resolved) {
         // Check that the use resolves to the declaration
-        auto resolved_identifier = graph.resolved_identifiers.Find(use);
-        ASSERT_TRUE(resolved_identifier);
         auto* resolved_node = resolved_identifier->Node();
         EXPECT_EQ(resolved_node, decl)
             << "resolved: " << (resolved_node ? resolved_node->TypeInfo().name : "<null>") << "\n"
             << "decl:     " << decl->TypeInfo().name;
+    } else {
+        auto* unresolved = resolved_identifier->Unresolved();
+        ASSERT_NE(unresolved, nullptr);
+        EXPECT_EQ(unresolved->name, "SYMBOL");
     }
 }
 
@@ -1177,51 +1197,6 @@
     EXPECT_EQ(resolved->BuiltinFunction(), builtin) << resolved->String(Symbols(), Diagnostics());
 }
 
-TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, ShadowedByGlobalVar) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::GlobalVar, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, ShadowedByStruct) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Struct, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, ShadowedByFunc) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Function, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
 INSTANTIATE_TEST_SUITE_P(Types,
                          ResolverDependencyGraphResolveToBuiltinFunc,
                          testing::Combine(testing::ValuesIn(kTypeUseKinds),
@@ -1258,79 +1233,29 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->BuiltinType(), type::ParseBuiltin(name))
+    EXPECT_EQ(resolved->BuiltinType(), builtin::ParseBuiltin(name))
         << resolved->String(Symbols(), Diagnostics());
 }
 
-TEST_P(ResolverDependencyGraphResolveToBuiltinType, ShadowedByGlobalVar) {
-    const auto use = std::get<0>(GetParam());
-    const std::string name = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(name);
-
-    auto* decl =
-        GlobalVar(symbol, name == "i32" ? ty.u32() : ty.i32(), type::AddressSpace::kPrivate);
-
-    SymbolTestHelper helper(this);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToBuiltinType, ShadowedByStruct) {
-    const auto use = std::get<0>(GetParam());
-    const std::string name = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(name);
-
-    auto* decl = Structure(symbol, utils::Vector{
-                                       Member("m", name == "i32" ? ty.u32() : ty.i32()),
-                                   });
-
-    SymbolTestHelper helper(this);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToBuiltinType, ShadowedByFunc) {
-    const auto use = std::get<0>(GetParam());
-    const auto name = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(name);
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Function, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
 INSTANTIATE_TEST_SUITE_P(Types,
                          ResolverDependencyGraphResolveToBuiltinType,
                          testing::Combine(testing::ValuesIn(kTypeUseKinds),
-                                          testing::ValuesIn(type::kBuiltinStrings)));
+                                          testing::ValuesIn(builtin::kBuiltinStrings)));
 
 INSTANTIATE_TEST_SUITE_P(Values,
                          ResolverDependencyGraphResolveToBuiltinType,
                          testing::Combine(testing::ValuesIn(kValueUseKinds),
-                                          testing::ValuesIn(type::kBuiltinStrings)));
+                                          testing::ValuesIn(builtin::kBuiltinStrings)));
 
 INSTANTIATE_TEST_SUITE_P(Functions,
                          ResolverDependencyGraphResolveToBuiltinType,
                          testing::Combine(testing::ValuesIn(kFuncUseKinds),
-                                          testing::ValuesIn(type::kBuiltinStrings)));
+                                          testing::ValuesIn(builtin::kBuiltinStrings)));
 
 }  // namespace resolve_to_builtin_type
 
 ////////////////////////////////////////////////////////////////////////////////
-// Resolve to type::Access tests
+// Resolve to builtin::Access tests
 ////////////////////////////////////////////////////////////////////////////////
 namespace resolve_to_access {
 
@@ -1348,74 +1273,29 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Access(), type::ParseAccess(name))
+    EXPECT_EQ(resolved->Access(), builtin::ParseAccess(name))
         << resolved->String(Symbols(), Diagnostics());
 }
 
-TEST_P(ResolverDependencyGraphResolveToAccess, ShadowedByGlobalVar) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::GlobalVar, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToAccess, ShadowedByStruct) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Struct, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToAccess, ShadowedByFunc) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Function, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
 INSTANTIATE_TEST_SUITE_P(Types,
                          ResolverDependencyGraphResolveToAccess,
                          testing::Combine(testing::ValuesIn(kTypeUseKinds),
-                                          testing::ValuesIn(type::kAccessStrings)));
+                                          testing::ValuesIn(builtin::kAccessStrings)));
 
 INSTANTIATE_TEST_SUITE_P(Values,
                          ResolverDependencyGraphResolveToAccess,
                          testing::Combine(testing::ValuesIn(kValueUseKinds),
-                                          testing::ValuesIn(type::kAccessStrings)));
+                                          testing::ValuesIn(builtin::kAccessStrings)));
 
 INSTANTIATE_TEST_SUITE_P(Functions,
                          ResolverDependencyGraphResolveToAccess,
                          testing::Combine(testing::ValuesIn(kFuncUseKinds),
-                                          testing::ValuesIn(type::kAccessStrings)));
+                                          testing::ValuesIn(builtin::kAccessStrings)));
 
 }  // namespace resolve_to_access
 
 ////////////////////////////////////////////////////////////////////////////////
-// Resolve to type::AddressSpace tests
+// Resolve to builtin::AddressSpace tests
 ////////////////////////////////////////////////////////////////////////////////
 namespace resolve_to_address_space {
 
@@ -1433,74 +1313,152 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->AddressSpace(), type::ParseAddressSpace(name))
+    EXPECT_EQ(resolved->AddressSpace(), builtin::ParseAddressSpace(name))
         << resolved->String(Symbols(), Diagnostics());
 }
 
-TEST_P(ResolverDependencyGraphResolveToAddressSpace, ShadowedByGlobalVar) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::GlobalVar, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToAddressSpace, ShadowedByStruct) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Struct, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToAddressSpace, ShadowedByFunc) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Function, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
 INSTANTIATE_TEST_SUITE_P(Types,
                          ResolverDependencyGraphResolveToAddressSpace,
                          testing::Combine(testing::ValuesIn(kTypeUseKinds),
-                                          testing::ValuesIn(type::kAddressSpaceStrings)));
+                                          testing::ValuesIn(builtin::kAddressSpaceStrings)));
 
 INSTANTIATE_TEST_SUITE_P(Values,
                          ResolverDependencyGraphResolveToAddressSpace,
                          testing::Combine(testing::ValuesIn(kValueUseKinds),
-                                          testing::ValuesIn(type::kAddressSpaceStrings)));
+                                          testing::ValuesIn(builtin::kAddressSpaceStrings)));
 
 INSTANTIATE_TEST_SUITE_P(Functions,
                          ResolverDependencyGraphResolveToAddressSpace,
                          testing::Combine(testing::ValuesIn(kFuncUseKinds),
-                                          testing::ValuesIn(type::kAddressSpaceStrings)));
+                                          testing::ValuesIn(builtin::kAddressSpaceStrings)));
 
 }  // namespace resolve_to_address_space
 
 ////////////////////////////////////////////////////////////////////////////////
-// Resolve to type::TexelFormat tests
+// Resolve to builtin::BuiltinValue tests
+////////////////////////////////////////////////////////////////////////////////
+namespace resolve_to_builtin_value {
+
+using ResolverDependencyGraphResolveToBuiltinValue =
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, const char*>>;
+
+TEST_P(ResolverDependencyGraphResolveToBuiltinValue, Resolve) {
+    const auto use = std::get<0>(GetParam());
+    const auto name = std::get<1>(GetParam());
+    const auto symbol = Symbols().New(name);
+
+    SymbolTestHelper helper(this);
+    auto* ident = helper.Add(use, symbol);
+    helper.Build();
+
+    auto resolved = Build().resolved_identifiers.Get(ident);
+    ASSERT_TRUE(resolved);
+    EXPECT_EQ(resolved->BuiltinValue(), builtin::ParseBuiltinValue(name))
+        << resolved->String(Symbols(), Diagnostics());
+}
+
+INSTANTIATE_TEST_SUITE_P(Types,
+                         ResolverDependencyGraphResolveToBuiltinValue,
+                         testing::Combine(testing::ValuesIn(kTypeUseKinds),
+                                          testing::ValuesIn(builtin::kBuiltinValueStrings)));
+
+INSTANTIATE_TEST_SUITE_P(Values,
+                         ResolverDependencyGraphResolveToBuiltinValue,
+                         testing::Combine(testing::ValuesIn(kValueUseKinds),
+                                          testing::ValuesIn(builtin::kBuiltinValueStrings)));
+
+INSTANTIATE_TEST_SUITE_P(Functions,
+                         ResolverDependencyGraphResolveToBuiltinValue,
+                         testing::Combine(testing::ValuesIn(kFuncUseKinds),
+                                          testing::ValuesIn(builtin::kBuiltinValueStrings)));
+
+}  // namespace resolve_to_builtin_value
+
+////////////////////////////////////////////////////////////////////////////////
+// Resolve to builtin::InterpolationSampling tests
+////////////////////////////////////////////////////////////////////////////////
+namespace resolve_to_interpolation_sampling {
+
+using ResolverDependencyGraphResolveToInterpolationSampling =
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, const char*>>;
+
+TEST_P(ResolverDependencyGraphResolveToInterpolationSampling, Resolve) {
+    const auto use = std::get<0>(GetParam());
+    const auto name = std::get<1>(GetParam());
+    const auto symbol = Symbols().New(name);
+
+    SymbolTestHelper helper(this);
+    auto* ident = helper.Add(use, symbol);
+    helper.Build();
+
+    auto resolved = Build().resolved_identifiers.Get(ident);
+    ASSERT_TRUE(resolved);
+    EXPECT_EQ(resolved->InterpolationSampling(), builtin::ParseInterpolationSampling(name))
+        << resolved->String(Symbols(), Diagnostics());
+}
+
+INSTANTIATE_TEST_SUITE_P(Types,
+                         ResolverDependencyGraphResolveToInterpolationSampling,
+                         testing::Combine(testing::ValuesIn(kTypeUseKinds),
+                                          testing::ValuesIn(builtin::kInterpolationTypeStrings)));
+
+INSTANTIATE_TEST_SUITE_P(Values,
+                         ResolverDependencyGraphResolveToInterpolationSampling,
+                         testing::Combine(testing::ValuesIn(kValueUseKinds),
+                                          testing::ValuesIn(builtin::kInterpolationTypeStrings)));
+
+INSTANTIATE_TEST_SUITE_P(Functions,
+                         ResolverDependencyGraphResolveToInterpolationSampling,
+                         testing::Combine(testing::ValuesIn(kFuncUseKinds),
+                                          testing::ValuesIn(builtin::kInterpolationTypeStrings)));
+
+}  // namespace resolve_to_interpolation_sampling
+
+////////////////////////////////////////////////////////////////////////////////
+// Resolve to builtin::InterpolationType tests
+////////////////////////////////////////////////////////////////////////////////
+namespace resolve_to_interpolation_sampling {
+
+using ResolverDependencyGraphResolveToInterpolationType =
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, const char*>>;
+
+TEST_P(ResolverDependencyGraphResolveToInterpolationType, Resolve) {
+    const auto use = std::get<0>(GetParam());
+    const auto name = std::get<1>(GetParam());
+    const auto symbol = Symbols().New(name);
+
+    SymbolTestHelper helper(this);
+    auto* ident = helper.Add(use, symbol);
+    helper.Build();
+
+    auto resolved = Build().resolved_identifiers.Get(ident);
+    ASSERT_TRUE(resolved);
+    EXPECT_EQ(resolved->InterpolationType(), builtin::ParseInterpolationType(name))
+        << resolved->String(Symbols(), Diagnostics());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    Types,
+    ResolverDependencyGraphResolveToInterpolationType,
+    testing::Combine(testing::ValuesIn(kTypeUseKinds),
+                     testing::ValuesIn(builtin::kInterpolationSamplingStrings)));
+
+INSTANTIATE_TEST_SUITE_P(
+    Values,
+    ResolverDependencyGraphResolveToInterpolationType,
+    testing::Combine(testing::ValuesIn(kValueUseKinds),
+                     testing::ValuesIn(builtin::kInterpolationSamplingStrings)));
+
+INSTANTIATE_TEST_SUITE_P(
+    Functions,
+    ResolverDependencyGraphResolveToInterpolationType,
+    testing::Combine(testing::ValuesIn(kFuncUseKinds),
+                     testing::ValuesIn(builtin::kInterpolationSamplingStrings)));
+
+}  // namespace resolve_to_interpolation_sampling
+
+////////////////////////////////////////////////////////////////////////////////
+// Resolve to builtin::TexelFormat tests
 ////////////////////////////////////////////////////////////////////////////////
 namespace resolve_to_texel_format {
 
@@ -1518,69 +1476,24 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->TexelFormat(), type::ParseTexelFormat(name))
+    EXPECT_EQ(resolved->TexelFormat(), builtin::ParseTexelFormat(name))
         << resolved->String(Symbols(), Diagnostics());
 }
 
-TEST_P(ResolverDependencyGraphResolveToTexelFormat, ShadowedByGlobalVar) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::GlobalVar, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToTexelFormat, ShadowedByStruct) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Struct, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
-TEST_P(ResolverDependencyGraphResolveToTexelFormat, ShadowedByFunc) {
-    const auto use = std::get<0>(GetParam());
-    const auto builtin = std::get<1>(GetParam());
-    const auto symbol = Symbols().New(utils::ToString(builtin));
-
-    SymbolTestHelper helper(this);
-    auto* decl = helper.Add(SymbolDeclKind::Function, symbol);
-    auto* ident = helper.Add(use, symbol);
-    helper.Build();
-
-    auto resolved = Build().resolved_identifiers.Get(ident);
-    ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
-}
-
 INSTANTIATE_TEST_SUITE_P(Types,
                          ResolverDependencyGraphResolveToTexelFormat,
                          testing::Combine(testing::ValuesIn(kTypeUseKinds),
-                                          testing::ValuesIn(type::kTexelFormatStrings)));
+                                          testing::ValuesIn(builtin::kTexelFormatStrings)));
 
 INSTANTIATE_TEST_SUITE_P(Values,
                          ResolverDependencyGraphResolveToTexelFormat,
                          testing::Combine(testing::ValuesIn(kValueUseKinds),
-                                          testing::ValuesIn(type::kTexelFormatStrings)));
+                                          testing::ValuesIn(builtin::kTexelFormatStrings)));
 
 INSTANTIATE_TEST_SUITE_P(Functions,
                          ResolverDependencyGraphResolveToTexelFormat,
                          testing::Combine(testing::ValuesIn(kFuncUseKinds),
-                                          testing::ValuesIn(type::kTexelFormatStrings)));
+                                          testing::ValuesIn(builtin::kTexelFormatStrings)));
 
 }  // namespace resolve_to_texel_format
 
@@ -1589,10 +1502,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 namespace shadowing {
 
-using ResolverDependencyGraphShadowTest =
+using ResolverDependencyGraphShadowScopeTest =
     ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolDeclKind>>;
 
-TEST_P(ResolverDependencyGraphShadowTest, Test) {
+TEST_P(ResolverDependencyGraphShadowScopeTest, Test) {
     const Symbol symbol = Sym("SYMBOL");
     const auto outer_kind = std::get<0>(GetParam());
     const auto inner_kind = std::get<1>(GetParam());
@@ -1615,18 +1528,107 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(LocalShadowGlobal,
-                         ResolverDependencyGraphShadowTest,
+                         ResolverDependencyGraphShadowScopeTest,
                          testing::Combine(testing::ValuesIn(kGlobalDeclKinds),
                                           testing::ValuesIn(kLocalDeclKinds)));
 
 INSTANTIATE_TEST_SUITE_P(NestedLocalShadowLocal,
-                         ResolverDependencyGraphShadowTest,
+                         ResolverDependencyGraphShadowScopeTest,
                          testing::Combine(testing::Values(SymbolDeclKind::Parameter,
                                                           SymbolDeclKind::LocalVar,
                                                           SymbolDeclKind::LocalLet),
                                           testing::Values(SymbolDeclKind::NestedLocalVar,
                                                           SymbolDeclKind::NestedLocalLet)));
 
+using ResolverDependencyGraphShadowKindTest =
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, const char*>>;
+
+TEST_P(ResolverDependencyGraphShadowKindTest, ShadowedByGlobalVar) {
+    const auto use = std::get<0>(GetParam());
+    const std::string_view name = std::get<1>(GetParam());
+    const auto symbol = Symbols().New(utils::ToString(name));
+
+    SymbolTestHelper helper(this);
+    auto* decl = GlobalVar(
+        symbol,  //
+        name == "i32" ? ty.u32() : ty.i32(),
+        name == "private" ? builtin::AddressSpace::kWorkgroup : builtin::AddressSpace::kPrivate);
+    auto* ident = helper.Add(use, symbol);
+    helper.Build();
+
+    auto resolved = Build().resolved_identifiers.Get(ident);
+    ASSERT_TRUE(resolved);
+    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
+}
+
+TEST_P(ResolverDependencyGraphShadowKindTest, ShadowedByStruct) {
+    const auto use = std::get<0>(GetParam());
+    const std::string_view name = std::get<1>(GetParam());
+    const auto symbol = Symbols().New(utils::ToString(name));
+
+    SymbolTestHelper helper(this);
+    auto* decl = Structure(symbol, utils::Vector{
+                                       Member("m", name == "i32" ? ty.u32() : ty.i32()),
+                                   });
+    auto* ident = helper.Add(use, symbol);
+    helper.Build();
+
+    auto resolved = Build().resolved_identifiers.Get(ident);
+    ASSERT_TRUE(resolved);
+    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
+}
+
+TEST_P(ResolverDependencyGraphShadowKindTest, ShadowedByFunc) {
+    const auto use = std::get<0>(GetParam());
+    const auto name = std::get<1>(GetParam());
+    const auto symbol = Symbols().New(utils::ToString(name));
+
+    SymbolTestHelper helper(this);
+    auto* decl = helper.Add(SymbolDeclKind::Function, symbol);
+    auto* ident = helper.Add(use, symbol);
+    helper.Build();
+
+    auto resolved = Build().resolved_identifiers.Get(ident);
+    ASSERT_TRUE(resolved);
+    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Symbols(), Diagnostics());
+}
+
+INSTANTIATE_TEST_SUITE_P(Access,
+                         ResolverDependencyGraphShadowKindTest,
+                         testing::Combine(testing::ValuesIn(kAllUseKinds),
+                                          testing::ValuesIn(builtin::kAccessStrings)));
+
+INSTANTIATE_TEST_SUITE_P(AddressSpace,
+                         ResolverDependencyGraphShadowKindTest,
+                         testing::Combine(testing::ValuesIn(kAllUseKinds),
+                                          testing::ValuesIn(builtin::kAddressSpaceStrings)));
+
+INSTANTIATE_TEST_SUITE_P(BuiltinType,
+                         ResolverDependencyGraphShadowKindTest,
+                         testing::Combine(testing::ValuesIn(kAllUseKinds),
+                                          testing::ValuesIn(builtin::kBuiltinStrings)));
+
+INSTANTIATE_TEST_SUITE_P(BuiltinFunction,
+                         ResolverDependencyGraphShadowKindTest,
+                         testing::Combine(testing::ValuesIn(kAllUseKinds),
+                                          testing::ValuesIn(builtin::kBuiltinStrings)));
+
+INSTANTIATE_TEST_SUITE_P(
+    InterpolationSampling,
+    ResolverDependencyGraphShadowKindTest,
+    testing::Combine(testing::ValuesIn(kAllUseKinds),
+                     testing::ValuesIn(builtin::kInterpolationSamplingStrings)));
+
+INSTANTIATE_TEST_SUITE_P(InterpolationType,
+                         ResolverDependencyGraphShadowKindTest,
+                         testing::Combine(testing::ValuesIn(kAllUseKinds),
+                                          testing::ValuesIn(builtin::kInterpolationTypeStrings)));
+
+INSTANTIATE_TEST_SUITE_P(TexelFormat,
+                         ResolverDependencyGraphShadowKindTest,
+                         testing::Combine(testing::ValuesIn(kAllUseKinds),
+                                          testing::ValuesIn(builtin::kTexelFormatStrings)));
+
 }  // namespace shadowing
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1649,7 +1651,7 @@
     const auto type_sym = Sym("TYPE");
     const auto func_sym = Sym("FUNC");
 
-    const auto* value_decl = GlobalVar(value_sym, ty.i32(), type::AddressSpace::kPrivate);
+    const auto* value_decl = GlobalVar(value_sym, ty.i32(), builtin::AddressSpace::kPrivate);
     const auto* type_decl = Alias(type_sym, ty.i32());
     const auto* func_decl = Func(func_sym, utils::Empty, ty.void_(), utils::Empty);
 
@@ -1667,6 +1669,7 @@
                       std::string(__FILE__) + ":" + std::to_string(line) + ": " + kind});
         return use;
     };
+
 #define V add_use(value_decl, Expr(value_sym), __LINE__, "V()")
 #define T add_use(type_decl, ty(type_sym), __LINE__, "T()")
 #define F add_use(func_decl, Ident(func_sym), __LINE__, "F()")
@@ -1685,6 +1688,9 @@
              Param(Sym(), T,
                    utils::Vector{
                        Location(V),  // Parameter attributes
+                       Builtin(V),
+                       Interpolate(V),
+                       Interpolate(V, V),
                    }),
          },
          T,  // Return type
@@ -1728,14 +1734,14 @@
     GlobalVar(Sym(), ty.array(T, V));
     GlobalVar(Sym(), ty.vec3(T));
     GlobalVar(Sym(), ty.mat3x2(T));
-    GlobalVar(Sym(), ty.pointer(T, type::AddressSpace::kPrivate));
+    GlobalVar(Sym(), ty.pointer(T, builtin::AddressSpace::kPrivate));
     GlobalVar(Sym(), ty.sampled_texture(type::TextureDimension::k2d, T));
     GlobalVar(Sym(), ty.depth_texture(type::TextureDimension::k2d));
     GlobalVar(Sym(), ty.depth_multisampled_texture(type::TextureDimension::k2d));
     GlobalVar(Sym(), ty.external_texture());
     GlobalVar(Sym(), ty.multisampled_texture(type::TextureDimension::k2d, T));
-    GlobalVar(Sym(), ty.storage_texture(type::TextureDimension::k2d, type::TexelFormat::kR32Float,
-                                        type::Access::kRead));
+    GlobalVar(Sym(), ty.storage_texture(type::TextureDimension::k2d,
+                                        builtin::TexelFormat::kR32Float, builtin::Access::kRead));
     GlobalVar(Sym(), ty.sampler(type::SamplerKind::kSampler));
 
     GlobalVar(Sym(), ty.i32(), utils::Vector{Binding(V), Group(V)});
diff --git a/src/tint/resolver/diagnostic_control_test.cc b/src/tint/resolver/diagnostic_control_test.cc
index 6d892fb..d7143c7 100644
--- a/src/tint/resolver/diagnostic_control_test.cc
+++ b/src/tint/resolver/diagnostic_control_test.cc
@@ -32,7 +32,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts);
@@ -42,7 +42,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
+    DiagnosticDirective(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts);
@@ -52,7 +52,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
+    DiagnosticDirective(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts);
@@ -62,7 +62,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kOff, "chromium_unreachable_code");
+    DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts);
@@ -72,7 +72,8 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaAttribute) {
-    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
+    auto* attr =
+        DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -83,7 +84,7 @@
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaAttribute) {
     auto* attr =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
+        DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -93,7 +94,8 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaAttribute) {
-    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
+    auto* attr =
+        DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -103,7 +105,8 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaAttribute) {
-    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "chromium_unreachable_code");
+    auto* attr =
+        DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -119,9 +122,9 @@
     //   return;
     //   return; // Should produce a warning
     // }
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
     auto* attr =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
+        DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -147,7 +150,7 @@
     // }
     {
         auto* attr =
-            DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "chromium_unreachable_code");
+            DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
         Func("foo", {}, ty.void_(),
              utils::Vector{
                  Return(),
@@ -164,7 +167,7 @@
     }
     {
         auto* attr =
-            DiagnosticAttribute(ast::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
+            DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
         Func("zoo", {}, ty.void_(),
              utils::Vector{
                  Return(),
@@ -215,7 +218,7 @@
                                     Return(),
                                     Return(Source{{34, 43}}),
                                 },
-                                attr(ast::DiagnosticSeverity::kInfo)),
+                                attr(builtin::DiagnosticSeverity::kInfo)),
                             Else(Block(utils::Vector{
                                 While(
                                     Expr(true), Block(
@@ -223,15 +226,15 @@
                                                         Return(),
                                                         Return(Source{{56, 65}}),
                                                     },
-                                                    attr(ast::DiagnosticSeverity::kOff))),
+                                                    attr(builtin::DiagnosticSeverity::kOff))),
                                 Return(),
                                 Return(Source{{78, 87}}),
                             }))),
                      },
-                     attr(ast::DiagnosticSeverity::kWarning)),
+                     attr(builtin::DiagnosticSeverity::kWarning)),
              }),
          },
-         attr(ast::DiagnosticSeverity::kOff));
+         attr(builtin::DiagnosticSeverity::kOff));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
     EXPECT_EQ(r()->error(), R"(34:43 note: code is unreachable
@@ -239,7 +242,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Directive) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError,
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError,
                         Ident(Source{{12, 34}}, "chromium_unreachable_cod"));
     EXPECT_TRUE(r()->Resolve()) << r()->error();
     EXPECT_EQ(r()->error(),
@@ -249,7 +252,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Attribute) {
-    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kError,
+    auto* attr = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
                                      Ident(Source{{12, 34}}, "chromium_unreachable_cod"));
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -260,17 +263,17 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameSameSeverity_Directive) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError,
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError,
                         Ident(Source{{12, 34}}, "chromium_unreachable_code"));
-    DiagnosticDirective(ast::DiagnosticSeverity::kError,
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError,
                         Ident(Source{{56, 78}}, "chromium_unreachable_code"));
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameDifferentSeverity_Directive) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError,
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError,
                         Ident(Source{{12, 34}}, "chromium_unreachable_code"));
-    DiagnosticDirective(ast::DiagnosticSeverity::kOff,
+    DiagnosticDirective(builtin::DiagnosticSeverity::kOff,
                         Ident(Source{{56, 78}}, "chromium_unreachable_code"));
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -279,9 +282,9 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameUnknownNameDifferentSeverity_Directive) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError,
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError,
                         Ident(Source{{12, 34}}, "chromium_unreachable_codes"));
-    DiagnosticDirective(ast::DiagnosticSeverity::kOff,
+    DiagnosticDirective(builtin::DiagnosticSeverity::kOff,
                         Ident(Source{{56, 78}}, "chromium_unreachable_codes"));
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -296,24 +299,24 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_DifferentUnknownNameDifferentSeverity_Directive) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_codes");
-    DiagnosticDirective(ast::DiagnosticSeverity::kOff, "chromium_unreachable_codex");
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_codes");
+    DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_codex");
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameSameSeverity_Attribute) {
-    auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kError,
+    auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
                                       Ident(Source{{12, 34}}, "chromium_unreachable_code"));
-    auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kError,
+    auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
                                       Ident(Source{{56, 78}}, "chromium_unreachable_code"));
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameDifferentSeverity_Attribute) {
-    auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kError,
+    auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
                                       Ident(Source{{12, 34}}, "chromium_unreachable_code"));
-    auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff,
+    auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
                                       Ident(Source{{56, 78}}, "chromium_unreachable_code"));
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
     EXPECT_FALSE(r()->Resolve());
@@ -323,9 +326,9 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameUnknownNameDifferentSeverity_Attribute) {
-    auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kError,
+    auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
                                       Ident(Source{{12, 34}}, "chromium_unreachable_codes"));
-    auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff,
+    auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
                                       Ident(Source{{56, 78}}, "chromium_unreachable_codes"));
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
     EXPECT_FALSE(r()->Resolve());
@@ -342,8 +345,9 @@
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_DifferentUnknownNameDifferentSeverity_Attribute) {
     auto* attr1 =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kError, "chromium_unreachable_codes");
-    auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "chromium_unreachable_codex");
+        DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_codes");
+    auto* attr2 =
+        DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_codex");
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
diff --git a/src/tint/resolver/entry_point_validation_test.cc b/src/tint/resolver/entry_point_validation_test.cc
index 98012ad..dac6cd2 100644
--- a/src/tint/resolver/entry_point_validation_test.cc
+++ b/src/tint/resolver/entry_point_validation_test.cc
@@ -16,6 +16,7 @@
 #include "src/tint/ast/location_attribute.h"
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/stage_attribute.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
@@ -94,7 +95,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: missing entry point IO attribute on return type");
+    EXPECT_EQ(r()->error(), R"(12:34 error: missing entry point IO attribute on return type)");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Multiple) {
@@ -116,7 +117,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
-13:43 note: previously consumed location(0))");
+13:43 note: previously consumed @location)");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
@@ -170,7 +171,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
-13:43 note: previously consumed location(0)
+13:43 note: previously consumed @location
 12:34 note: while analyzing entry point 'main')");
 }
 
@@ -226,9 +227,8 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(
-        r()->error(),
-        R"(12:34 error: builtin(frag_depth) attribute appears multiple times as pipeline output
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: @builtin(frag_depth) appears multiple times as pipeline output
 12:34 note: while analyzing entry point 'main')");
 }
 
@@ -265,7 +265,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "13:43 error: missing entry point IO attribute on parameter");
+    EXPECT_EQ(r()->error(), R"(13:43 error: missing entry point IO attribute on parameter)");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Multiple) {
@@ -287,7 +287,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
-13:43 note: previously consumed location(0))");
+13:43 note: previously consumed @location)");
 }
 
 TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
@@ -341,7 +341,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
-13:43 note: previously consumed location(0)
+13:43 note: previously consumed @location
 12:34 note: while analyzing entry point 'main')");
 }
 
@@ -396,8 +396,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: builtin(sample_index) attribute appears multiple times as "
-              "pipeline input");
+              "12:34 error: @builtin(sample_index) appears multiple times as pipeline input");
 }
 
 TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
@@ -432,9 +431,8 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(
-        r()->error(),
-        R"(12:34 error: builtin(sample_index) attribute appears multiple times as pipeline input
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: @builtin(sample_index) appears multiple times as pipeline input
 12:34 note: while analyzing entry point 'main')");
 }
 
@@ -456,14 +454,14 @@
     // enable chromium_experimental_push_constant;
     // var<push_constant> a : u32;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar("a", ty.u32(), type::AddressSpace::kPushConstant);
+    GlobalVar("a", ty.u32(), builtin::AddressSpace::kPushConstant);
 
     EXPECT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverEntryPointValidationTest, PushConstantDisallowedWithoutEnable) {
     // var<push_constant> a : u32;
-    GlobalVar(Source{{1, 2}}, "a", ty.u32(), type::AddressSpace::kPushConstant);
+    GlobalVar(Source{{1, 2}}, "a", ty.u32(), builtin::AddressSpace::kPushConstant);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -473,7 +471,7 @@
 
 TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithIgnoreAddressSpaceAttribute) {
     // var<push_constant> a : u32; // With ast::DisabledValidation::kIgnoreAddressSpace
-    GlobalVar("a", ty.u32(), type::AddressSpace::kPushConstant,
+    GlobalVar("a", ty.u32(), builtin::AddressSpace::kPushConstant,
               utils::Vector{Disable(ast::DisabledValidation::kIgnoreAddressSpace)});
 
     EXPECT_TRUE(r()->Resolve());
@@ -486,7 +484,7 @@
     //   _ = a;
     // }
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar("a", ty.u32(), type::AddressSpace::kPushConstant);
+    GlobalVar("a", ty.u32(), builtin::AddressSpace::kPushConstant);
 
     Func("main", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
          utils::Vector{Stage(ast::PipelineStage::kCompute),
@@ -504,8 +502,8 @@
     //   _ = b;
     // }
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar(Source{{1, 2}}, "a", ty.u32(), type::AddressSpace::kPushConstant);
-    GlobalVar(Source{{3, 4}}, "b", ty.u32(), type::AddressSpace::kPushConstant);
+    GlobalVar(Source{{1, 2}}, "a", ty.u32(), builtin::AddressSpace::kPushConstant);
+    GlobalVar(Source{{3, 4}}, "b", ty.u32(), builtin::AddressSpace::kPushConstant);
 
     Func(Source{{5, 6}}, "main", {}, ty.void_(),
          utils::Vector{Assign(Phony(), "a"), Assign(Phony(), "b")},
@@ -535,8 +533,8 @@
     //   uses_b();
     // }
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar(Source{{1, 2}}, "a", ty.u32(), type::AddressSpace::kPushConstant);
-    GlobalVar(Source{{3, 4}}, "b", ty.u32(), type::AddressSpace::kPushConstant);
+    GlobalVar(Source{{1, 2}}, "a", ty.u32(), builtin::AddressSpace::kPushConstant);
+    GlobalVar(Source{{3, 4}}, "b", ty.u32(), builtin::AddressSpace::kPushConstant);
 
     Func(Source{{5, 6}}, "uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")});
     Func(Source{{7, 8}}, "uses_b", {}, ty.void_(), utils::Vector{Assign(Phony(), "b")});
@@ -568,8 +566,8 @@
     //   _ = a;
     // }
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar("a", ty.u32(), type::AddressSpace::kPushConstant);
-    GlobalVar("b", ty.u32(), type::AddressSpace::kPushConstant);
+    GlobalVar("a", ty.u32(), builtin::AddressSpace::kPushConstant);
+    GlobalVar("b", ty.u32(), builtin::AddressSpace::kPushConstant);
 
     Func("uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
          utils::Vector{Stage(ast::PipelineStage::kCompute),
@@ -785,10 +783,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: cannot apply 'location' attribute to declaration of "
-              "type 'bool'\n"
-              "34:56 note: 'location' attribute must only be applied to "
-              "declarations of numeric scalar or numeric vector type");
+              R"(12:34 error: cannot apply @location to declaration of type 'bool'
+34:56 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadType_Output_Array) {
@@ -808,10 +804,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: cannot apply 'location' attribute to declaration of "
-              "type 'array<f32, 2>'\n"
-              "34:56 note: 'location' attribute must only be applied to "
-              "declarations of numeric scalar or numeric vector type");
+              R"(12:34 error: cannot apply @location to declaration of type 'array<f32, 2>'
+34:56 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_Struct) {
@@ -838,10 +832,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: cannot apply 'location' attribute to declaration of "
-              "type 'Input'\n"
-              "13:43 note: 'location' attribute must only be applied to "
-              "declarations of numeric scalar or numeric vector type");
+              R"(12:34 error: cannot apply @location to declaration of type 'Input'
+13:43 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_Struct_NestedStruct) {
@@ -872,8 +864,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "14:52 error: nested structures cannot be used for entry point IO\n"
-              "12:34 note: while analyzing entry point 'main'");
+              R"(14:52 error: nested structures cannot be used for entry point IO
+12:34 note: while analyzing entry point 'main')");
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_Struct_RuntimeArray) {
@@ -898,10 +890,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "13:43 error: cannot apply 'location' attribute to declaration of "
-              "type 'array<f32>'\n"
-              "note: 'location' attribute must only be applied to declarations "
-              "of numeric scalar or numeric vector type");
+              R"(13:43 error: cannot apply @location to declaration of type 'array<f32>'
+note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Input) {
@@ -927,10 +917,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "34:56 error: cannot apply 'location' attribute to declaration of "
-              "type 'array<i32>'\n"
-              "12:34 note: 'location' attribute must only be applied to "
-              "declarations of numeric scalar or numeric vector type");
+              R"(34:56 error: cannot apply @location to declaration of type 'array<i32>'
+12:34 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Output) {
@@ -954,10 +942,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "34:56 error: cannot apply 'location' attribute to declaration of "
-              "type 'atomic<i32>'\n"
-              "12:34 note: 'location' attribute must only be applied to "
-              "declarations of numeric scalar or numeric vector type");
+              R"(34:56 error: cannot apply @location to declaration of type 'atomic<i32>'
+12:34 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Unused) {
@@ -971,10 +957,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "34:56 error: cannot apply 'location' attribute to declaration of "
-              "type 'mat3x2<f32>'\n"
-              "12:34 note: 'location' attribute must only be applied to "
-              "declarations of numeric scalar or numeric vector type");
+              R"(34:56 error: cannot apply @location to declaration of type 'mat3x2<f32>'
+12:34 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct_Valid) {
@@ -1026,11 +1010,8 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: cannot apply 'location' attribute to declaration of "
-              "type 'Output'\n"
-              "13:43 note: 'location' attribute must only be applied to "
-              "declarations of numeric scalar or numeric vector type");
+    EXPECT_EQ(r()->error(), R"(12:34 error: cannot apply @location to declaration of type 'Output'
+13:43 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct_NestedStruct) {
@@ -1059,8 +1040,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "14:52 error: nested structures cannot be used for entry point IO\n"
-              "12:34 note: while analyzing entry point 'main'");
+              R"(14:52 error: nested structures cannot be used for entry point IO
+12:34 note: while analyzing entry point 'main')");
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct_RuntimeArray) {
@@ -1085,10 +1066,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "13:43 error: cannot apply 'location' attribute to declaration of "
-              "type 'array<f32>'\n"
-              "12:34 note: 'location' attribute must only be applied to "
-              "declarations of numeric scalar or numeric vector type");
+              R"(13:43 error: cannot apply @location to declaration of type 'array<f32>'
+12:34 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocation_Input) {
@@ -1105,7 +1084,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for compute shader output");
+    EXPECT_EQ(r()->error(), R"(12:34 error: attribute is not valid for compute shader output)");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocation_Output) {
@@ -1120,7 +1099,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for compute shader inputs");
+    EXPECT_EQ(r()->error(), R"(12:34 error: attribute is not valid for compute shader inputs)");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Output) {
@@ -1186,7 +1165,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: location(1) attribute appears multiple times");
+    EXPECT_EQ(r()->error(), R"(12:34 error: @location(1) appears multiple times)");
 }
 
 TEST_F(LocationAttributeTests, Duplicate_struct) {
@@ -1219,8 +1198,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "34:56 error: location(1) attribute appears multiple times\n"
-              "12:34 note: while analyzing entry point 'main'");
+              R"(34:56 error: @location(1) appears multiple times
+12:34 note: while analyzing entry point 'main')");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/expression_kind_test.cc b/src/tint/resolver/expression_kind_test.cc
index dc3d8a8..2ceffa2 100644
--- a/src/tint/resolver/expression_kind_test.cc
+++ b/src/tint/resolver/expression_kind_test.cc
@@ -27,7 +27,11 @@
     kAddressSpace,
     kBuiltinFunction,
     kBuiltinType,
+    kBuiltinValue,
     kFunction,
+    kInterpolationSampling,
+    kInterpolationType,
+    kParameter,
     kStruct,
     kTexelFormat,
     kTypeAlias,
@@ -44,8 +48,16 @@
             return out << "Def::kBuiltinFunction";
         case Def::kBuiltinType:
             return out << "Def::kBuiltinType";
+        case Def::kBuiltinValue:
+            return out << "Def::kBuiltinValue";
         case Def::kFunction:
             return out << "Def::kFunction";
+        case Def::kInterpolationSampling:
+            return out << "Def::kInterpolationSampling";
+        case Def::kInterpolationType:
+            return out << "Def::kInterpolationType";
+        case Def::kParameter:
+            return out << "Def::kParameter";
         case Def::kStruct:
             return out << "Def::kStruct";
         case Def::kTexelFormat:
@@ -62,9 +74,12 @@
     kAccess,
     kAddressSpace,
     kBinaryOp,
+    kBuiltinValue,
     kCallExpr,
     kCallStmt,
     kFunctionReturnType,
+    kInterpolationSampling,
+    kInterpolationType,
     kMemberType,
     kTexelFormat,
     kValueExpression,
@@ -80,12 +95,18 @@
             return out << "Use::kAddressSpace";
         case Use::kBinaryOp:
             return out << "Use::kBinaryOp";
+        case Use::kBuiltinValue:
+            return out << "Use::kBuiltinValue";
         case Use::kCallExpr:
             return out << "Use::kCallExpr";
         case Use::kCallStmt:
             return out << "Use::kCallStmt";
         case Use::kFunctionReturnType:
             return out << "Use::kFunctionReturnType";
+        case Use::kInterpolationSampling:
+            return out << "Use::kInterpolationSampling";
+        case Use::kInterpolationType:
+            return out << "Use::kInterpolationType";
         case Use::kMemberType:
             return out << "Use::kMemberType";
         case Use::kTexelFormat:
@@ -120,14 +141,19 @@
 TEST_P(ResolverExpressionKindTest, Test) {
     Symbol sym;
     std::function<void(const sem::Expression*)> check_expr;
+
+    utils::Vector<const ast::Parameter*, 2> fn_params;
+    utils::Vector<const ast::Statement*, 2> fn_stmts;
+    utils::Vector<const ast::Attribute*, 2> fn_attrs;
+
     switch (GetParam().def) {
         case Def::kAccess: {
             sym = Sym("write");
             check_expr = [](const sem::Expression* expr) {
                 ASSERT_NE(expr, nullptr);
-                auto* enum_expr = expr->As<sem::BuiltinEnumExpression<type::Access>>();
+                auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::Access>>();
                 ASSERT_NE(enum_expr, nullptr);
-                EXPECT_EQ(enum_expr->Value(), type::Access::kWrite);
+                EXPECT_EQ(enum_expr->Value(), builtin::Access::kWrite);
             };
             break;
         }
@@ -135,9 +161,9 @@
             sym = Sym("workgroup");
             check_expr = [](const sem::Expression* expr) {
                 ASSERT_NE(expr, nullptr);
-                auto* enum_expr = expr->As<sem::BuiltinEnumExpression<type::AddressSpace>>();
+                auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::AddressSpace>>();
                 ASSERT_NE(enum_expr, nullptr);
-                EXPECT_EQ(enum_expr->Value(), type::AddressSpace::kWorkgroup);
+                EXPECT_EQ(enum_expr->Value(), builtin::AddressSpace::kWorkgroup);
             };
             break;
         }
@@ -156,9 +182,19 @@
             };
             break;
         }
+        case Def::kBuiltinValue: {
+            sym = Sym("position");
+            check_expr = [](const sem::Expression* expr) {
+                ASSERT_NE(expr, nullptr);
+                auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::BuiltinValue>>();
+                ASSERT_NE(enum_expr, nullptr);
+                EXPECT_EQ(enum_expr->Value(), builtin::BuiltinValue::kPosition);
+            };
+            break;
+        }
         case Def::kFunction: {
-            auto* fn = Func(kDefSource, "FUNCTION", utils::Empty, ty.i32(), Return(1_i));
             sym = Sym("FUNCTION");
+            auto* fn = Func(kDefSource, sym, utils::Empty, ty.i32(), Return(1_i));
             check_expr = [fn](const sem::Expression* expr) {
                 ASSERT_NE(expr, nullptr);
                 auto* fn_expr = expr->As<sem::FunctionExpression>();
@@ -167,9 +203,43 @@
             };
             break;
         }
+        case Def::kInterpolationSampling: {
+            sym = Sym("center");
+            check_expr = [](const sem::Expression* expr) {
+                ASSERT_NE(expr, nullptr);
+                auto* enum_expr =
+                    expr->As<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>();
+                ASSERT_NE(enum_expr, nullptr);
+                EXPECT_EQ(enum_expr->Value(), builtin::InterpolationSampling::kCenter);
+            };
+            break;
+        }
+        case Def::kInterpolationType: {
+            sym = Sym("linear");
+            check_expr = [](const sem::Expression* expr) {
+                ASSERT_NE(expr, nullptr);
+                auto* enum_expr =
+                    expr->As<sem::BuiltinEnumExpression<builtin::InterpolationType>>();
+                ASSERT_NE(enum_expr, nullptr);
+                EXPECT_EQ(enum_expr->Value(), builtin::InterpolationType::kLinear);
+            };
+            break;
+        }
+        case Def::kParameter: {
+            sym = Sym("PARAMETER");
+            auto* param = Param(kDefSource, sym, ty.i32());
+            fn_params.Push(param);
+            check_expr = [param](const sem::Expression* expr) {
+                ASSERT_NE(expr, nullptr);
+                auto* user = expr->As<sem::VariableUser>();
+                ASSERT_NE(user, nullptr);
+                EXPECT_EQ(user->Variable()->Declaration(), param);
+            };
+            break;
+        }
         case Def::kStruct: {
-            auto* s = Structure(kDefSource, "STRUCT", utils::Vector{Member("m", ty.i32())});
             sym = Sym("STRUCT");
+            auto* s = Structure(kDefSource, sym, utils::Vector{Member("m", ty.i32())});
             check_expr = [s](const sem::Expression* expr) {
                 ASSERT_NE(expr, nullptr);
                 auto* ty_expr = expr->As<sem::TypeExpression>();
@@ -184,15 +254,15 @@
             sym = Sym("rgba8unorm");
             check_expr = [](const sem::Expression* expr) {
                 ASSERT_NE(expr, nullptr);
-                auto* enum_expr = expr->As<sem::BuiltinEnumExpression<type::TexelFormat>>();
+                auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::TexelFormat>>();
                 ASSERT_NE(enum_expr, nullptr);
-                EXPECT_EQ(enum_expr->Value(), type::TexelFormat::kRgba8Unorm);
+                EXPECT_EQ(enum_expr->Value(), builtin::TexelFormat::kRgba8Unorm);
             };
             break;
         }
         case Def::kTypeAlias: {
-            Alias(kDefSource, "ALIAS", ty.i32());
             sym = Sym("ALIAS");
+            Alias(kDefSource, sym, ty.i32());
             check_expr = [](const sem::Expression* expr) {
                 ASSERT_NE(expr, nullptr);
                 auto* ty_expr = expr->As<sem::TypeExpression>();
@@ -202,8 +272,8 @@
             break;
         }
         case Def::kVariable: {
-            auto* c = GlobalConst(kDefSource, "VARIABLE", Expr(1_i));
             sym = Sym("VARIABLE");
+            auto* c = GlobalConst(kDefSource, sym, Expr(1_i));
             check_expr = [c](const sem::Expression* expr) {
                 ASSERT_NE(expr, nullptr);
                 auto* var_expr = expr->As<sem::VariableUser>();
@@ -221,38 +291,67 @@
             break;
         case Use::kAddressSpace:
             Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
-            Func("f", utils::Vector{Param("p", ty("ptr", expr, ty.f32()))}, ty.void_(),
+            Func(Symbols().New(), utils::Vector{Param("p", ty("ptr", expr, ty.f32()))}, ty.void_(),
                  utils::Empty);
             break;
         case Use::kCallExpr:
-            Func("f", utils::Empty, ty.void_(), Decl(Var("v", Call(expr))));
+            fn_stmts.Push(Decl(Var("v", Call(expr))));
             break;
         case Use::kCallStmt:
-            Func("f", utils::Empty, ty.void_(), CallStmt(Call(expr)));
+            fn_stmts.Push(CallStmt(Call(expr)));
             break;
         case Use::kBinaryOp:
-            GlobalVar("v", type::AddressSpace::kPrivate, Mul(1_a, expr));
+            fn_stmts.Push(Decl(Var("v", Mul(1_a, expr))));
+            break;
+        case Use::kBuiltinValue:
+            Func(Symbols().New(),
+                 utils::Vector{Param("p", ty.vec4<f32>(), utils::Vector{Builtin(expr)})},
+                 ty.void_(), utils::Empty, utils::Vector{Stage(ast::PipelineStage::kFragment)});
             break;
         case Use::kFunctionReturnType:
-            Func("f", utils::Empty, ty(expr), Return(Call(sym)));
+            Func(Symbols().New(), utils::Empty, ty(expr), Return(Call(sym)));
             break;
+        case Use::kInterpolationSampling: {
+            fn_params.Push(Param("p", ty.vec4<f32>(),
+                                 utils::Vector{
+                                     Location(0_a),
+                                     Interpolate(builtin::InterpolationType::kLinear, expr),
+                                 }));
+            fn_attrs.Push(Stage(ast::PipelineStage::kFragment));
+            break;
+        }
+        case Use::kInterpolationType: {
+            fn_params.Push(Param("p", ty.vec4<f32>(),
+                                 utils::Vector{
+                                     Location(0_a),
+                                     Interpolate(expr, builtin::InterpolationSampling::kCenter),
+                                 }));
+            fn_attrs.Push(Stage(ast::PipelineStage::kFragment));
+            break;
+        }
         case Use::kMemberType:
-            Structure("s", utils::Vector{Member("m", ty(expr))});
+            Structure(Symbols().New(), utils::Vector{Member("m", ty(expr))});
             break;
         case Use::kTexelFormat:
-            GlobalVar("v", ty("texture_storage_2d", ty(expr), "write"), Group(0_u), Binding(0_u));
+            GlobalVar(Symbols().New(), ty("texture_storage_2d", ty(expr), "write"), Group(0_u),
+                      Binding(0_u));
             break;
         case Use::kValueExpression:
-            GlobalVar("v", type::AddressSpace::kPrivate, expr);
+            fn_stmts.Push(Decl(Var("v", expr)));
             break;
         case Use::kVariableType:
-            GlobalVar("v", type::AddressSpace::kPrivate, ty(expr));
+            fn_stmts.Push(Decl(Var("v", ty(expr))));
             break;
         case Use::kUnaryOp:
-            GlobalVar("v", type::AddressSpace::kPrivate, Negation(expr));
+            fn_stmts.Push(Assign(Phony(), Negation(expr)));
             break;
     }
 
+    if (!fn_params.IsEmpty() || !fn_stmts.IsEmpty()) {
+        Func(Symbols().New(), std::move(fn_params), ty.void_(), std::move(fn_stmts),
+             std::move(fn_attrs));
+    }
+
     if (GetParam().error == kPass) {
         EXPECT_TRUE(r()->Resolve());
         EXPECT_EQ(r()->error(), "");
@@ -271,9 +370,15 @@
         {Def::kAccess, Use::kAddressSpace,
          R"(5:6 error: cannot use access 'write' as address space)"},
         {Def::kAccess, Use::kBinaryOp, R"(5:6 error: cannot use access 'write' as value)"},
+        {Def::kAccess, Use::kBuiltinValue,
+         R"(5:6 error: cannot use access 'write' as builtin value)"},
         {Def::kAccess, Use::kCallExpr, R"(5:6 error: cannot use access 'write' as call target)"},
         {Def::kAccess, Use::kCallStmt, R"(5:6 error: cannot use access 'write' as call target)"},
         {Def::kAccess, Use::kFunctionReturnType, R"(5:6 error: cannot use access 'write' as type)"},
+        {Def::kAccess, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use access 'write' as interpolation sampling)"},
+        {Def::kAccess, Use::kInterpolationType,
+         R"(5:6 error: cannot use access 'write' as interpolation type)"},
         {Def::kAccess, Use::kMemberType, R"(5:6 error: cannot use access 'write' as type)"},
         {Def::kAccess, Use::kTexelFormat,
          R"(5:6 error: cannot use access 'write' as texel format)"},
@@ -286,12 +391,18 @@
         {Def::kAddressSpace, Use::kAddressSpace, kPass},
         {Def::kAddressSpace, Use::kBinaryOp,
          R"(5:6 error: cannot use address space 'workgroup' as value)"},
+        {Def::kAddressSpace, Use::kBuiltinValue,
+         R"(5:6 error: cannot use address space 'workgroup' as builtin value)"},
         {Def::kAddressSpace, Use::kCallExpr,
          R"(5:6 error: cannot use address space 'workgroup' as call target)"},
         {Def::kAddressSpace, Use::kCallStmt,
          R"(5:6 error: cannot use address space 'workgroup' as call target)"},
         {Def::kAddressSpace, Use::kFunctionReturnType,
          R"(5:6 error: cannot use address space 'workgroup' as type)"},
+        {Def::kAddressSpace, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use address space 'workgroup' as interpolation sampling)"},
+        {Def::kAddressSpace, Use::kInterpolationType,
+         R"(5:6 error: cannot use address space 'workgroup' as interpolation type)"},
         {Def::kAddressSpace, Use::kMemberType,
          R"(5:6 error: cannot use address space 'workgroup' as type)"},
         {Def::kAddressSpace, Use::kTexelFormat,
@@ -309,9 +420,15 @@
          R"(7:8 error: missing '(' for builtin function call)"},
         {Def::kBuiltinFunction, Use::kBinaryOp,
          R"(7:8 error: missing '(' for builtin function call)"},
+        {Def::kBuiltinFunction, Use::kBuiltinValue,
+         R"(7:8 error: missing '(' for builtin function call)"},
         {Def::kBuiltinFunction, Use::kCallStmt, kPass},
         {Def::kBuiltinFunction, Use::kFunctionReturnType,
          R"(7:8 error: missing '(' for builtin function call)"},
+        {Def::kBuiltinFunction, Use::kInterpolationSampling,
+         R"(7:8 error: missing '(' for builtin function call)"},
+        {Def::kBuiltinFunction, Use::kInterpolationType,
+         R"(7:8 error: missing '(' for builtin function call)"},
         {Def::kBuiltinFunction, Use::kMemberType,
          R"(7:8 error: missing '(' for builtin function call)"},
         {Def::kBuiltinFunction, Use::kTexelFormat,
@@ -328,19 +445,53 @@
          R"(5:6 error: cannot use type 'vec4<f32>' as address space)"},
         {Def::kBuiltinType, Use::kBinaryOp,
          R"(5:6 error: cannot use type 'vec4<f32>' as value
-7:8 note: are you missing '()' for type initializer?)"},
+7:8 note: are you missing '()' for value constructor?)"},
+        {Def::kBuiltinType, Use::kBuiltinValue,
+         R"(5:6 error: cannot use type 'vec4<f32>' as builtin value)"},
         {Def::kBuiltinType, Use::kCallExpr, kPass},
         {Def::kBuiltinType, Use::kFunctionReturnType, kPass},
+        {Def::kBuiltinType, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use type 'vec4<f32>' as interpolation sampling)"},
+        {Def::kBuiltinType, Use::kInterpolationType,
+         R"(5:6 error: cannot use type 'vec4<f32>' as interpolation type)"},
         {Def::kBuiltinType, Use::kMemberType, kPass},
         {Def::kBuiltinType, Use::kTexelFormat,
          R"(5:6 error: cannot use type 'vec4<f32>' as texel format)"},
         {Def::kBuiltinType, Use::kValueExpression,
          R"(5:6 error: cannot use type 'vec4<f32>' as value
-7:8 note: are you missing '()' for type initializer?)"},
+7:8 note: are you missing '()' for value constructor?)"},
         {Def::kBuiltinType, Use::kVariableType, kPass},
         {Def::kBuiltinType, Use::kUnaryOp,
          R"(5:6 error: cannot use type 'vec4<f32>' as value
-7:8 note: are you missing '()' for type initializer?)"},
+7:8 note: are you missing '()' for value constructor?)"},
+
+        {Def::kBuiltinValue, Use::kAccess,
+         R"(5:6 error: cannot use builtin value 'position' as access)"},
+        {Def::kBuiltinValue, Use::kAddressSpace,
+         R"(5:6 error: cannot use builtin value 'position' as address space)"},
+        {Def::kBuiltinValue, Use::kBinaryOp,
+         R"(5:6 error: cannot use builtin value 'position' as value)"},
+        {Def::kBuiltinValue, Use::kBuiltinValue, kPass},
+        {Def::kBuiltinValue, Use::kCallStmt,
+         R"(5:6 error: cannot use builtin value 'position' as call target)"},
+        {Def::kBuiltinValue, Use::kCallExpr,
+         R"(5:6 error: cannot use builtin value 'position' as call target)"},
+        {Def::kBuiltinValue, Use::kFunctionReturnType,
+         R"(5:6 error: cannot use builtin value 'position' as type)"},
+        {Def::kBuiltinValue, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use builtin value 'position' as interpolation sampling)"},
+        {Def::kBuiltinValue, Use::kInterpolationType,
+         R"(5:6 error: cannot use builtin value 'position' as interpolation type)"},
+        {Def::kBuiltinValue, Use::kMemberType,
+         R"(5:6 error: cannot use builtin value 'position' as type)"},
+        {Def::kBuiltinValue, Use::kTexelFormat,
+         R"(5:6 error: cannot use builtin value 'position' as texel format)"},
+        {Def::kBuiltinValue, Use::kValueExpression,
+         R"(5:6 error: cannot use builtin value 'position' as value)"},
+        {Def::kBuiltinValue, Use::kVariableType,
+         R"(5:6 error: cannot use builtin value 'position' as type)"},
+        {Def::kBuiltinValue, Use::kUnaryOp,
+         R"(5:6 error: cannot use builtin value 'position' as value)"},
 
         {Def::kFunction, Use::kAccess, R"(5:6 error: cannot use function 'FUNCTION' as access
 1:2 note: function 'FUNCTION' declared here)"},
@@ -349,11 +500,20 @@
 1:2 note: function 'FUNCTION' declared here)"},
         {Def::kFunction, Use::kBinaryOp, R"(5:6 error: cannot use function 'FUNCTION' as value
 1:2 note: function 'FUNCTION' declared here)"},
+        {Def::kFunction, Use::kBuiltinValue,
+         R"(5:6 error: cannot use function 'FUNCTION' as builtin value
+1:2 note: function 'FUNCTION' declared here)"},
         {Def::kFunction, Use::kCallExpr, kPass},
         {Def::kFunction, Use::kCallStmt, kPass},
         {Def::kFunction, Use::kFunctionReturnType,
          R"(5:6 error: cannot use function 'FUNCTION' as type
 1:2 note: function 'FUNCTION' declared here)"},
+        {Def::kFunction, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use function 'FUNCTION' as interpolation sampling
+1:2 note: function 'FUNCTION' declared here)"},
+        {Def::kFunction, Use::kInterpolationType,
+         R"(5:6 error: cannot use function 'FUNCTION' as interpolation type
+1:2 note: function 'FUNCTION' declared here)"},
         {Def::kFunction, Use::kMemberType,
          R"(5:6 error: cannot use function 'FUNCTION' as type
 1:2 note: function 'FUNCTION' declared here)"},
@@ -369,24 +529,105 @@
         {Def::kFunction, Use::kUnaryOp, R"(5:6 error: cannot use function 'FUNCTION' as value
 1:2 note: function 'FUNCTION' declared here)"},
 
-        {Def::kStruct, Use::kAccess, R"(5:6 error: cannot use type 'STRUCT' as access)"},
+        {Def::kInterpolationSampling, Use::kAccess,
+         R"(5:6 error: cannot use interpolation sampling 'center' as access)"},
+        {Def::kInterpolationSampling, Use::kAddressSpace,
+         R"(5:6 error: cannot use interpolation sampling 'center' as address space)"},
+        {Def::kInterpolationSampling, Use::kBinaryOp,
+         R"(5:6 error: cannot use interpolation sampling 'center' as value)"},
+        {Def::kInterpolationSampling, Use::kBuiltinValue,
+         R"(5:6 error: cannot use interpolation sampling 'center' as builtin value)"},
+        {Def::kInterpolationSampling, Use::kCallStmt,
+         R"(5:6 error: cannot use interpolation sampling 'center' as call target)"},
+        {Def::kInterpolationSampling, Use::kCallExpr,
+         R"(5:6 error: cannot use interpolation sampling 'center' as call target)"},
+        {Def::kInterpolationSampling, Use::kFunctionReturnType,
+         R"(5:6 error: cannot use interpolation sampling 'center' as type)"},
+        {Def::kInterpolationSampling, Use::kInterpolationSampling, kPass},
+        {Def::kInterpolationSampling, Use::kInterpolationType,
+         R"(5:6 error: cannot use interpolation sampling 'center' as interpolation type)"},
+        {Def::kInterpolationSampling, Use::kMemberType,
+         R"(5:6 error: cannot use interpolation sampling 'center' as type)"},
+        {Def::kInterpolationSampling, Use::kTexelFormat,
+         R"(5:6 error: cannot use interpolation sampling 'center' as texel format)"},
+        {Def::kInterpolationSampling, Use::kValueExpression,
+         R"(5:6 error: cannot use interpolation sampling 'center' as value)"},
+        {Def::kInterpolationSampling, Use::kVariableType,
+         R"(5:6 error: cannot use interpolation sampling 'center' as type)"},
+        {Def::kInterpolationSampling, Use::kUnaryOp,
+         R"(5:6 error: cannot use interpolation sampling 'center' as value)"},
+
+        {Def::kInterpolationType, Use::kAccess,
+         R"(5:6 error: cannot use interpolation type 'linear' as access)"},
+        {Def::kInterpolationType, Use::kAddressSpace,
+         R"(5:6 error: cannot use interpolation type 'linear' as address space)"},
+        {Def::kInterpolationType, Use::kBinaryOp,
+         R"(5:6 error: cannot use interpolation type 'linear' as value)"},
+        {Def::kInterpolationType, Use::kBuiltinValue,
+         R"(5:6 error: cannot use interpolation type 'linear' as builtin value)"},
+        {Def::kInterpolationType, Use::kCallStmt,
+         R"(5:6 error: cannot use interpolation type 'linear' as call target)"},
+        {Def::kInterpolationType, Use::kCallExpr,
+         R"(5:6 error: cannot use interpolation type 'linear' as call target)"},
+        {Def::kInterpolationType, Use::kFunctionReturnType,
+         R"(5:6 error: cannot use interpolation type 'linear' as type)"},
+        {Def::kInterpolationType, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use interpolation type 'linear' as interpolation sampling)"},
+        {Def::kInterpolationType, Use::kInterpolationType, kPass},
+        {Def::kInterpolationType, Use::kMemberType,
+         R"(5:6 error: cannot use interpolation type 'linear' as type)"},
+        {Def::kInterpolationType, Use::kTexelFormat,
+         R"(5:6 error: cannot use interpolation type 'linear' as texel format)"},
+        {Def::kInterpolationType, Use::kValueExpression,
+         R"(5:6 error: cannot use interpolation type 'linear' as value)"},
+        {Def::kInterpolationType, Use::kVariableType,
+         R"(5:6 error: cannot use interpolation type 'linear' as type)"},
+        {Def::kInterpolationType, Use::kUnaryOp,
+         R"(5:6 error: cannot use interpolation type 'linear' as value)"},
+
+        {Def::kParameter, Use::kBinaryOp, kPass},
+        {Def::kParameter, Use::kCallStmt,
+         R"(5:6 error: cannot use parameter 'PARAMETER' as call target
+1:2 note: parameter 'PARAMETER' declared here)"},
+        {Def::kParameter, Use::kCallExpr,
+         R"(5:6 error: cannot use parameter 'PARAMETER' as call target
+1:2 note: parameter 'PARAMETER' declared here)"},
+        {Def::kParameter, Use::kValueExpression, kPass},
+        {Def::kParameter, Use::kVariableType,
+         R"(5:6 error: cannot use parameter 'PARAMETER' as type
+1:2 note: parameter 'PARAMETER' declared here)"},
+        {Def::kParameter, Use::kUnaryOp, kPass},
+
+        {Def::kStruct, Use::kAccess, R"(5:6 error: cannot use type 'STRUCT' as access
+1:2 note: struct 'STRUCT' declared here)"},
         {Def::kStruct, Use::kAddressSpace,
-         R"(5:6 error: cannot use type 'STRUCT' as address space)"},
+         R"(5:6 error: cannot use type 'STRUCT' as address space
+1:2 note: struct 'STRUCT' declared here)"},
         {Def::kStruct, Use::kBinaryOp, R"(5:6 error: cannot use type 'STRUCT' as value
-7:8 note: are you missing '()' for type initializer?
+1:2 note: struct 'STRUCT' declared here
+7:8 note: are you missing '()' for value constructor?)"},
+        {Def::kStruct, Use::kBuiltinValue,
+         R"(5:6 error: cannot use type 'STRUCT' as builtin value
 1:2 note: struct 'STRUCT' declared here)"},
         {Def::kStruct, Use::kFunctionReturnType, kPass},
+        {Def::kStruct, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use type 'STRUCT' as interpolation sampling
+1:2 note: struct 'STRUCT' declared here)"},
+        {Def::kStruct, Use::kInterpolationType,
+         R"(5:6 error: cannot use type 'STRUCT' as interpolation type
+1:2 note: struct 'STRUCT' declared here)"},
         {Def::kStruct, Use::kMemberType, kPass},
-        {Def::kStruct, Use::kTexelFormat, R"(5:6 error: cannot use type 'STRUCT' as texel format)"},
+        {Def::kStruct, Use::kTexelFormat, R"(5:6 error: cannot use type 'STRUCT' as texel format
+1:2 note: struct 'STRUCT' declared here)"},
         {Def::kStruct, Use::kValueExpression,
          R"(5:6 error: cannot use type 'STRUCT' as value
-7:8 note: are you missing '()' for type initializer?
-1:2 note: struct 'STRUCT' declared here)"},
+1:2 note: struct 'STRUCT' declared here
+7:8 note: are you missing '()' for value constructor?)"},
         {Def::kStruct, Use::kVariableType, kPass},
         {Def::kStruct, Use::kUnaryOp,
          R"(5:6 error: cannot use type 'STRUCT' as value
-7:8 note: are you missing '()' for type initializer?
-1:2 note: struct 'STRUCT' declared here)"},
+1:2 note: struct 'STRUCT' declared here
+7:8 note: are you missing '()' for value constructor?)"},
 
         {Def::kTexelFormat, Use::kAccess,
          R"(5:6 error: cannot use texel format 'rgba8unorm' as access)"},
@@ -394,12 +635,18 @@
          R"(5:6 error: cannot use texel format 'rgba8unorm' as address space)"},
         {Def::kTexelFormat, Use::kBinaryOp,
          R"(5:6 error: cannot use texel format 'rgba8unorm' as value)"},
+        {Def::kTexelFormat, Use::kBuiltinValue,
+         R"(5:6 error: cannot use texel format 'rgba8unorm' as builtin value)"},
         {Def::kTexelFormat, Use::kCallExpr,
          R"(5:6 error: cannot use texel format 'rgba8unorm' as call target)"},
         {Def::kTexelFormat, Use::kCallStmt,
          R"(5:6 error: cannot use texel format 'rgba8unorm' as call target)"},
         {Def::kTexelFormat, Use::kFunctionReturnType,
          R"(5:6 error: cannot use texel format 'rgba8unorm' as type)"},
+        {Def::kTexelFormat, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use texel format 'rgba8unorm' as interpolation sampling)"},
+        {Def::kTexelFormat, Use::kInterpolationType,
+         R"(5:6 error: cannot use texel format 'rgba8unorm' as interpolation type)"},
         {Def::kTexelFormat, Use::kMemberType,
          R"(5:6 error: cannot use texel format 'rgba8unorm' as type)"},
         {Def::kTexelFormat, Use::kTexelFormat, kPass},
@@ -415,18 +662,24 @@
          R"(5:6 error: cannot use type 'i32' as address space)"},
         {Def::kTypeAlias, Use::kBinaryOp,
          R"(5:6 error: cannot use type 'i32' as value
-7:8 note: are you missing '()' for type initializer?)"},
+7:8 note: are you missing '()' for value constructor?)"},
+        {Def::kTypeAlias, Use::kBuiltinValue,
+         R"(5:6 error: cannot use type 'i32' as builtin value)"},
         {Def::kTypeAlias, Use::kCallExpr, kPass},
         {Def::kTypeAlias, Use::kFunctionReturnType, kPass},
+        {Def::kTypeAlias, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use type 'i32' as interpolation sampling)"},
+        {Def::kTypeAlias, Use::kInterpolationType,
+         R"(5:6 error: cannot use type 'i32' as interpolation type)"},
         {Def::kTypeAlias, Use::kMemberType, kPass},
         {Def::kTypeAlias, Use::kTexelFormat, R"(5:6 error: cannot use type 'i32' as texel format)"},
         {Def::kTypeAlias, Use::kValueExpression,
          R"(5:6 error: cannot use type 'i32' as value
-7:8 note: are you missing '()' for type initializer?)"},
+7:8 note: are you missing '()' for value constructor?)"},
         {Def::kTypeAlias, Use::kVariableType, kPass},
         {Def::kTypeAlias, Use::kUnaryOp,
          R"(5:6 error: cannot use type 'i32' as value
-7:8 note: are you missing '()' for type initializer?)"},
+7:8 note: are you missing '()' for value constructor?)"},
 
         {Def::kVariable, Use::kAccess, R"(5:6 error: cannot use const 'VARIABLE' as access
 1:2 note: const 'VARIABLE' declared here)"},
@@ -434,6 +687,9 @@
          R"(5:6 error: cannot use const 'VARIABLE' as address space
 1:2 note: const 'VARIABLE' declared here)"},
         {Def::kVariable, Use::kBinaryOp, kPass},
+        {Def::kVariable, Use::kBuiltinValue,
+         R"(5:6 error: cannot use const 'VARIABLE' as builtin value
+1:2 note: const 'VARIABLE' declared here)"},
         {Def::kVariable, Use::kCallStmt,
          R"(5:6 error: cannot use const 'VARIABLE' as call target
 1:2 note: const 'VARIABLE' declared here)"},
@@ -443,6 +699,12 @@
         {Def::kVariable, Use::kFunctionReturnType,
          R"(5:6 error: cannot use const 'VARIABLE' as type
 1:2 note: const 'VARIABLE' declared here)"},
+        {Def::kVariable, Use::kInterpolationSampling,
+         R"(5:6 error: cannot use const 'VARIABLE' as interpolation sampling
+1:2 note: const 'VARIABLE' declared here)"},
+        {Def::kVariable, Use::kInterpolationType,
+         R"(5:6 error: cannot use const 'VARIABLE' as interpolation type
+1:2 note: const 'VARIABLE' declared here)"},
         {Def::kVariable, Use::kMemberType,
          R"(5:6 error: cannot use const 'VARIABLE' as type
 1:2 note: const 'VARIABLE' declared here)"},
diff --git a/src/tint/resolver/f16_extension_test.cc b/src/tint/resolver/f16_extension_test.cc
index d767919..0868208 100644
--- a/src/tint/resolver/f16_extension_test.cc
+++ b/src/tint/resolver/f16_extension_test.cc
@@ -29,14 +29,14 @@
     // var<private> v : f16;
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("v", ty.f16(), type::AddressSpace::kPrivate);
+    GlobalVar("v", ty.f16(), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverF16ExtensionTest, TypeUsedWithoutExtension) {
     // var<private> v : f16;
-    GlobalVar("v", ty.f16(Source{{12, 34}}), type::AddressSpace::kPrivate);
+    GlobalVar("v", ty.f16(Source{{12, 34}}), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
@@ -47,14 +47,14 @@
     // var<private> v : vec2<f16>;
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("v", ty.vec2<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("v", ty.vec2<f16>(), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverF16ExtensionTest, Vec2TypeUsedWithoutExtension) {
     // var<private> v : vec2<f16>;
-    GlobalVar("v", ty.vec2(ty.f16(Source{{12, 34}})), type::AddressSpace::kPrivate);
+    GlobalVar("v", ty.vec2(ty.f16(Source{{12, 34}})), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
@@ -65,14 +65,14 @@
     // var<private> v = vec2<f16>();
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("v", vec2<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec2<f16>(), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverF16ExtensionTest, Vec2TypeInitUsedWithoutExtension) {
     // var<private> v = vec2<f16>();
-    GlobalVar("v", Call(ty.vec2(ty.f16(Source{{12, 34}}))), type::AddressSpace::kPrivate);
+    GlobalVar("v", Call(ty.vec2(ty.f16(Source{{12, 34}}))), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
@@ -83,14 +83,14 @@
     // var<private> v = vec2<f16>(vec2<f32>());
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("v", vec2<f16>(vec2<f32>()), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec2<f16>(vec2<f32>()), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverF16ExtensionTest, Vec2TypeConvUsedWithoutExtension) {
     // var<private> v = vec2<f16>(vec2<f32>());
-    GlobalVar("v", vec2(ty.f16(Source{{12, 34}}), vec2<f32>()), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec2(ty.f16(Source{{12, 34}}), vec2<f32>()), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
@@ -101,14 +101,14 @@
     // var<private> v = 16h;
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("v", Expr(16_h), type::AddressSpace::kPrivate);
+    GlobalVar("v", Expr(16_h), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverF16ExtensionTest, F16LiteralUsedWithoutExtension) {
     // var<private> v = 16h;
-    GlobalVar("v", Expr(Source{{12, 34}}, 16_h), type::AddressSpace::kPrivate);
+    GlobalVar("v", Expr(Source{{12, 34}}, 16_h), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
@@ -121,14 +121,14 @@
     // var<private> v : vec2h;
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("v", ty(Source{{12, 34}}, GetParam()), type::AddressSpace::kPrivate);
+    GlobalVar("v", ty(Source{{12, 34}}, GetParam()), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(ResolverF16ExtensionBuiltinTypeAliasTest, Vec2hTypeUsedWithoutExtension) {
     // var<private> v : vec2h;
-    GlobalVar("v", ty(Source{{12, 34}}, GetParam()), type::AddressSpace::kPrivate);
+    GlobalVar("v", ty(Source{{12, 34}}, GetParam()), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc
index 7ef446a..3a0275f 100644
--- a/src/tint/resolver/function_validation_test.cc
+++ b/src/tint/resolver/function_validation_test.cc
@@ -15,6 +15,7 @@
 #include "src/tint/ast/discard_statement.h"
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/stage_attribute.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
@@ -39,7 +40,7 @@
 TEST_F(ResolverFunctionValidationTest, ParameterMayShadowGlobal) {
     // var<private> common_name : f32;
     // fn func(common_name : f32) { }
-    GlobalVar("common_name", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("common_name", ty.f32(), builtin::AddressSpace::kPrivate);
     Func("func", utils::Vector{Param("common_name", ty.f32())}, ty.void_(), utils::Empty);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -420,7 +421,7 @@
          utils::Vector{
              Return(1_i),
          });
-    GlobalVar("x", Call(Source{{12, 34}}, "F"), type::AddressSpace::kPrivate);
+    GlobalVar("x", Call(Source{{12, 34}}, "F"), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(12:34 error: functions cannot be called at module-scope)");
@@ -486,18 +487,6 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverFunctionValidationTest, FunctionParamsConst) {
-    Func("foo", utils::Vector{Param(Sym("arg"), ty.i32())}, ty.void_(),
-         utils::Vector{
-             Assign(Expr(Source{{12, 34}}, "arg"), Expr(1_i)),
-             Return(),
-         });
-
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: cannot assign to function parameter\nnote: 'arg' is declared here:");
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_ConstU32) {
     // const x = 4u;
     // const y = 8u;
@@ -874,7 +863,7 @@
     // var<private> x = 64i;
     // @compute @workgroup_size(x)
     // fn main() {}
-    GlobalVar("x", ty.i32(), type::AddressSpace::kPrivate, Expr(64_i));
+    GlobalVar("x", ty.i32(), builtin::AddressSpace::kPrivate, Expr(64_i));
     Func("main", utils::Empty, ty.void_(), utils::Empty,
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -890,7 +879,7 @@
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr_x) {
     // @compute @workgroup_size(1 << 2 + 4)
     // fn main() {}
-    GlobalVar("x", ty.i32(), type::AddressSpace::kPrivate, Expr(0_i));
+    GlobalVar("x", ty.i32(), builtin::AddressSpace::kPrivate, Expr(0_i));
     Func("main", utils::Empty, ty.void_(), utils::Empty,
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -906,7 +895,7 @@
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr_y) {
     // @compute @workgroup_size(1, 1 << 2 + 4)
     // fn main() {}
-    GlobalVar("x", ty.i32(), type::AddressSpace::kPrivate, Expr(0_i));
+    GlobalVar("x", ty.i32(), builtin::AddressSpace::kPrivate, Expr(0_i));
     Func("main", utils::Empty, ty.void_(), utils::Empty,
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -922,7 +911,7 @@
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr_z) {
     // @compute @workgroup_size(1, 1, 1 << 2 + 4)
     // fn main() {}
-    GlobalVar("x", ty.i32(), type::AddressSpace::kPrivate, Expr(0_i));
+    GlobalVar("x", ty.i32(), builtin::AddressSpace::kPrivate, Expr(0_i));
     Func("main", utils::Empty, ty.void_(), utils::Empty,
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -936,7 +925,7 @@
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
-    auto ret_type = ty.pointer(Source{{12, 34}}, ty.i32(), type::AddressSpace::kFunction);
+    auto ret_type = ty.pointer(Source{{12, 34}}, ty.i32(), builtin::AddressSpace::kFunction);
     Func("f", utils::Empty, ret_type, utils::Empty);
 
     EXPECT_FALSE(r()->Resolve());
@@ -1049,7 +1038,7 @@
     kInvalid,
 };
 struct TestParams {
-    type::AddressSpace address_space;
+    builtin::AddressSpace address_space;
     Expectation expectation;
 };
 
@@ -1069,11 +1058,14 @@
         ss << param.address_space;
         EXPECT_FALSE(r()->Resolve());
         if (param.expectation == Expectation::kInvalid) {
-            EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: '" + ss.str() + "'");
+            std::string err = R"(12:34 error: unresolved address space '${addr_space}'
+12:34 note: Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')";
+            err = utils::ReplaceAll(err, "${addr_space}", utils::ToString(param.address_space));
+            EXPECT_EQ(r()->error(), err);
         } else {
             EXPECT_EQ(r()->error(),
-                      "12:34 error: function parameter of pointer type cannot be in '" + ss.str() +
-                          "' address space");
+                      "12:34 error: function parameter of pointer type cannot be in '" +
+                          utils::ToString(param.address_space) + "' address space");
         }
     }
 }
@@ -1088,31 +1080,34 @@
         param.expectation == Expectation::kPassWithFullPtrParameterExtension) {
         ASSERT_TRUE(r()->Resolve()) << r()->error();
     } else {
-        std::stringstream ss;
-        ss << param.address_space;
         EXPECT_FALSE(r()->Resolve());
         if (param.expectation == Expectation::kInvalid) {
-            EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: '" + ss.str() + "'");
+            std::string err = R"(12:34 error: unresolved address space '${addr_space}'
+12:34 note: Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')";
+            err = utils::ReplaceAll(err, "${addr_space}", utils::ToString(param.address_space));
+            EXPECT_EQ(r()->error(), err);
         } else {
             EXPECT_EQ(r()->error(),
-                      "12:34 error: function parameter of pointer type cannot be in '" + ss.str() +
-                          "' address space");
+                      "12:34 error: function parameter of pointer type cannot be in '" +
+                          utils::ToString(param.address_space) + "' address space");
         }
     }
 }
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverFunctionParameterValidationTest,
-    testing::Values(
-        TestParams{type::AddressSpace::kNone, Expectation::kInvalid},
-        TestParams{type::AddressSpace::kIn, Expectation::kInvalid},
-        TestParams{type::AddressSpace::kOut, Expectation::kInvalid},
-        TestParams{type::AddressSpace::kUniform, Expectation::kPassWithFullPtrParameterExtension},
-        TestParams{type::AddressSpace::kWorkgroup, Expectation::kPassWithFullPtrParameterExtension},
-        TestParams{type::AddressSpace::kHandle, Expectation::kInvalid},
-        TestParams{type::AddressSpace::kStorage, Expectation::kPassWithFullPtrParameterExtension},
-        TestParams{type::AddressSpace::kPrivate, Expectation::kAlwaysPass},
-        TestParams{type::AddressSpace::kFunction, Expectation::kAlwaysPass}));
+    testing::Values(TestParams{builtin::AddressSpace::kUndefined, Expectation::kInvalid},
+                    TestParams{builtin::AddressSpace::kIn, Expectation::kAlwaysFail},
+                    TestParams{builtin::AddressSpace::kOut, Expectation::kAlwaysFail},
+                    TestParams{builtin::AddressSpace::kUniform,
+                               Expectation::kPassWithFullPtrParameterExtension},
+                    TestParams{builtin::AddressSpace::kWorkgroup,
+                               Expectation::kPassWithFullPtrParameterExtension},
+                    TestParams{builtin::AddressSpace::kHandle, Expectation::kInvalid},
+                    TestParams{builtin::AddressSpace::kStorage,
+                               Expectation::kPassWithFullPtrParameterExtension},
+                    TestParams{builtin::AddressSpace::kPrivate, Expectation::kAlwaysPass},
+                    TestParams{builtin::AddressSpace::kFunction, Expectation::kAlwaysPass}));
 
 }  // namespace
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/host_shareable_validation_test.cc b/src/tint/resolver/host_shareable_validation_test.cc
index b518b57..b32c669 100644
--- a/src/tint/resolver/host_shareable_validation_test.cc
+++ b/src/tint/resolver/host_shareable_validation_test.cc
@@ -29,8 +29,8 @@
     auto* s =
         Structure("S", utils::Vector{Member(Source{{56, 78}}, "x", ty.bool_(Source{{12, 34}}))});
 
-    GlobalVar(Source{{90, 12}}, "g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-              Binding(0_a), Group(0_a));
+    GlobalVar(Source{{90, 12}}, "g", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -45,8 +45,8 @@
     auto* s = Structure(
         "S", utils::Vector{Member(Source{{56, 78}}, "x", ty.vec3<bool>(Source{{12, 34}}))});
 
-    GlobalVar(Source{{90, 12}}, "g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-              Binding(0_a), Group(0_a));
+    GlobalVar(Source{{90, 12}}, "g", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -62,8 +62,8 @@
     auto* s =
         Structure("S", utils::Vector{Member(Source{{56, 78}}, "x", ty(Source{{12, 34}}, "a1"))});
     auto* a2 = Alias("a2", ty.Of(s));
-    GlobalVar(Source{{90, 12}}, "g", ty.Of(a2), type::AddressSpace::kStorage, type::Access::kRead,
-              Binding(0_a), Group(0_a));
+    GlobalVar(Source{{90, 12}}, "g", ty.Of(a2), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -81,8 +81,8 @@
 
     auto* s = Structure("S", utils::Vector{Member(Source{{7, 8}}, "m", ty.Of(i3))});
 
-    GlobalVar(Source{{9, 10}}, "g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-              Binding(0_a), Group(0_a));
+    GlobalVar(Source{{9, 10}}, "g", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -120,8 +120,8 @@
 
     auto* s = Structure("S", utils::Vector{Member(Source{{7, 8}}, "m", ty.Of(i3))});
 
-    GlobalVar(Source{{9, 10}}, "g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-              Binding(0_a), Group(0_a));
+    GlobalVar(Source{{9, 10}}, "g", ty.Of(s), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
diff --git a/src/tint/resolver/increment_decrement_validation_test.cc b/src/tint/resolver/increment_decrement_validation_test.cc
index 7cca736..c5a6c98 100644
--- a/src/tint/resolver/increment_decrement_validation_test.cc
+++ b/src/tint/resolver/increment_decrement_validation_test.cc
@@ -64,8 +64,8 @@
     // var a : i32;
     // let b : ptr<function,i32> = &a;
     // *b++;
-    auto* var_a = Var("a", ty.i32(), type::AddressSpace::kFunction);
-    auto* var_b = Let("b", ty.pointer<i32>(type::AddressSpace::kFunction), AddressOf(Expr("a")));
+    auto* var_a = Var("a", ty.i32(), builtin::AddressSpace::kFunction);
+    auto* var_b = Let("b", ty.pointer<i32>(builtin::AddressSpace::kFunction), AddressOf(Expr("a")));
     WrapInFunction(var_a, var_b, Increment(Source{{12, 34}}, Deref("b")));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -127,7 +127,7 @@
 TEST_F(ResolverIncrementDecrementValidationTest, Atomic) {
     // var<workgroup> a : atomic<i32>;
     // a++;
-    GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), type::AddressSpace::kWorkgroup);
+    GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), builtin::AddressSpace::kWorkgroup);
     WrapInFunction(Increment(Expr(Source{{56, 78}}, "a")));
 
     EXPECT_FALSE(r()->Resolve());
@@ -193,8 +193,8 @@
     // {
     //   a++;
     // }
-    GlobalVar(Source{{12, 34}}, "a", ty.i32(), type::AddressSpace::kStorage, type::Access::kRead,
-              Group(0_a), Binding(0_a));
+    GlobalVar(Source{{12, 34}}, "a", ty.i32(), builtin::AddressSpace::kStorage,
+              builtin::Access::kRead, Group(0_a), Binding(0_a));
     WrapInFunction(Increment(Source{{56, 78}}, "a"));
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/inferred_type_test.cc b/src/tint/resolver/inferred_type_test.cc
index 8a609d2..ab2478b 100644
--- a/src/tint/resolver/inferred_type_test.cc
+++ b/src/tint/resolver/inferred_type_test.cc
@@ -97,7 +97,7 @@
 
     // var a = <type initializer>;
     auto* ctor_expr = params.create_value(*this, 0);
-    auto* var = GlobalVar("a", type::AddressSpace::kPrivate, ctor_expr);
+    auto* var = GlobalVar("a", builtin::AddressSpace::kPrivate, ctor_expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
     EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
@@ -124,7 +124,7 @@
 
     // var a = <type initializer>;
     auto* ctor_expr = params.create_value(*this, 0);
-    auto* var = Var("a", type::AddressSpace::kFunction, ctor_expr);
+    auto* var = Var("a", builtin::AddressSpace::kFunction, ctor_expr);
     WrapInFunction(var);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -139,7 +139,7 @@
         create<type::U32>(), create<type::ConstantArrayCount>(10u), 4u, 4u * 10u, 4u, 4u);
 
     auto* ctor_expr = Call(type);
-    auto* var = Var("a", type::AddressSpace::kFunction, ctor_expr);
+    auto* var = Var("a", builtin::AddressSpace::kFunction, ctor_expr);
     WrapInFunction(var);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -158,7 +158,7 @@
 
     auto* ctor_expr = Call(ty.Of(str));
 
-    auto* var = Var("a", type::AddressSpace::kFunction, ctor_expr);
+    auto* var = Var("a", builtin::AddressSpace::kFunction, ctor_expr);
     WrapInFunction(var);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/init_conv_intrinsic.h b/src/tint/resolver/init_conv_intrinsic.h
deleted file mode 100644
index 07bb45b..0000000
--- a/src/tint/resolver/init_conv_intrinsic.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2021 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.
-
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/resolver/init_conv_intrinsic.h.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
-#ifndef SRC_TINT_RESOLVER_INIT_CONV_INTRINSIC_H_
-#define SRC_TINT_RESOLVER_INIT_CONV_INTRINSIC_H_
-
-#include <cstdint>
-
-namespace tint::resolver {
-
-/// InitConvIntrinsic is an enumerator of types that have a initializer or converter overload
-/// declared in the intrinsic table.
-enum class InitConvIntrinsic {
-    kNone = -1,
-    kI32,
-    kU32,
-    kF32,
-    kF16,
-    kBool,
-    kVec2,
-    kVec3,
-    kVec4,
-    kMat2x2,
-    kMat2x3,
-    kMat2x4,
-    kMat3x2,
-    kMat3x3,
-    kMat3x4,
-    kMat4x2,
-    kMat4x3,
-    kMat4x4,
-};
-
-/// @returns the name of the type.
-const char* str(InitConvIntrinsic i);
-
-/// @param n the width of the vector
-/// @return the InitConvIntrinsic for a vector of width `n`
-inline InitConvIntrinsic VectorInitConvIntrinsic(uint32_t n) {
-    switch (n) {
-        case 2:
-            return InitConvIntrinsic::kVec2;
-        case 3:
-            return InitConvIntrinsic::kVec3;
-        case 4:
-            return InitConvIntrinsic::kVec4;
-    }
-    return InitConvIntrinsic::kNone;
-}
-
-/// @param c the number of columns in the matrix
-/// @param r the number of rows in the matrix
-/// @return the InitConvIntrinsic for a matrix with `c` columns and `r` rows
-inline InitConvIntrinsic MatrixInitConvIntrinsic(uint32_t c, uint32_t r) {
-    switch ((c - 2) * 3 + (r - 2)) {
-        case 0:
-            return InitConvIntrinsic::kMat2x2;
-        case 1:
-            return InitConvIntrinsic::kMat2x3;
-        case 2:
-            return InitConvIntrinsic::kMat2x4;
-        case 3:
-            return InitConvIntrinsic::kMat3x2;
-        case 4:
-            return InitConvIntrinsic::kMat3x3;
-        case 5:
-            return InitConvIntrinsic::kMat3x4;
-        case 6:
-            return InitConvIntrinsic::kMat4x2;
-        case 7:
-            return InitConvIntrinsic::kMat4x3;
-        case 8:
-            return InitConvIntrinsic::kMat4x4;
-    }
-    return InitConvIntrinsic::kNone;
-}
-
-}  // namespace tint::resolver
-
-#endif  // SRC_TINT_RESOLVER_INIT_CONV_INTRINSIC_H_
diff --git a/src/tint/resolver/init_conv_intrinsic.h.tmpl b/src/tint/resolver/init_conv_intrinsic.h.tmpl
deleted file mode 100644
index 5f1281b..0000000
--- a/src/tint/resolver/init_conv_intrinsic.h.tmpl
+++ /dev/null
@@ -1,76 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate init_conv_intrinsic.h
-
-To update the generated file, run:
-    ./tools/run gen
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-#ifndef SRC_TINT_RESOLVER_INIT_CONV_INTRINSIC_H_
-#define SRC_TINT_RESOLVER_INIT_CONV_INTRINSIC_H_
-
-#include <cstdint>
-
-namespace tint::resolver {
-
-/// InitConvIntrinsic is an enumerator of types that have a initializer or converter overload
-/// declared in the intrinsic table.
-enum class InitConvIntrinsic {
-    kNone = -1,
-{{- range Sem.InitializersAndConverters }}
-    k{{Title .Name}},
-{{- end }}
-};
-
-/// @returns the name of the type.
-const char* str(InitConvIntrinsic i);
-
-/// @param n the width of the vector
-/// @return the InitConvIntrinsic for a vector of width `n`
-inline InitConvIntrinsic VectorInitConvIntrinsic(uint32_t n) {
-    switch (n) {
-        case 2:
-            return InitConvIntrinsic::kVec2;
-        case 3:
-            return InitConvIntrinsic::kVec3;
-        case 4:
-            return InitConvIntrinsic::kVec4;
-    }
-    return InitConvIntrinsic::kNone;
-}
-
-/// @param c the number of columns in the matrix
-/// @param r the number of rows in the matrix
-/// @return the InitConvIntrinsic for a matrix with `c` columns and `r` rows
-inline InitConvIntrinsic MatrixInitConvIntrinsic(uint32_t c, uint32_t r) {
-    switch ((c - 2) * 3 + (r - 2)) {
-        case 0:
-            return InitConvIntrinsic::kMat2x2;
-        case 1:
-            return InitConvIntrinsic::kMat2x3;
-        case 2:
-            return InitConvIntrinsic::kMat2x4;
-        case 3:
-            return InitConvIntrinsic::kMat3x2;
-        case 4:
-            return InitConvIntrinsic::kMat3x3;
-        case 5:
-            return InitConvIntrinsic::kMat3x4;
-        case 6:
-            return InitConvIntrinsic::kMat4x2;
-        case 7:
-            return InitConvIntrinsic::kMat4x3;
-        case 8:
-            return InitConvIntrinsic::kMat4x4;
-    }
-    return InitConvIntrinsic::kNone;
-}
-
-}  // namespace tint::resolver
-
-#endif  // SRC_TINT_RESOLVER_INIT_CONV_INTRINSIC_H_
diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc
index 7c58444..17927db 100644
--- a/src/tint/resolver/intrinsic_table.cc
+++ b/src/tint/resolver/intrinsic_table.cc
@@ -22,8 +22,8 @@
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/evaluation_stage.h"
 #include "src/tint/sem/pipeline_stage_set.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/type/abstract_float.h"
 #include "src/tint/type/abstract_int.h"
 #include "src/tint/type/abstract_numeric.h"
@@ -328,9 +328,9 @@
 // TODO(bclayton): See if we can move more of this hand-rolled code to the
 // template
 ////////////////////////////////////////////////////////////////////////////////
-using TexelFormat = type::TexelFormat;
-using Access = type::Access;
-using AddressSpace = type::AddressSpace;
+using TexelFormat = builtin::TexelFormat;
+using Access = builtin::Access;
+using AddressSpace = builtin::AddressSpace;
 using ParameterUsage = sem::ParameterUsage;
 using PipelineStage = ast::PipelineStage;
 
@@ -338,11 +338,12 @@
 enum class OverloadFlag {
     kIsBuiltin,                 // The overload is a builtin ('fn')
     kIsOperator,                // The overload is an operator ('op')
-    kIsInitializer,             // The overload is a type initializer ('ctor')
-    kIsConverter,               // The overload is a type converter ('conv')
+    kIsConstructor,             // The overload is a value constructor ('ctor')
+    kIsConverter,               // The overload is a value converter ('conv')
     kSupportsVertexPipeline,    // The overload can be used in vertex shaders
     kSupportsFragmentPipeline,  // The overload can be used in fragment shaders
     kSupportsComputePipeline,   // The overload can be used in compute shaders
+    kMustUse,                   // The overload cannot be called as a statement
     kIsDeprecated,              // The overload is deprecated
 };
 
@@ -560,8 +561,8 @@
 }
 
 const type::Pointer* build_ptr(MatchState& state, Number S, const type::Type* T, Number& A) {
-    return state.builder.create<type::Pointer>(T, static_cast<type::AddressSpace>(S.Value()),
-                                               static_cast<type::Access>(A.Value()));
+    return state.builder.create<type::Pointer>(T, static_cast<builtin::AddressSpace>(S.Value()),
+                                               static_cast<builtin::Access>(A.Value()));
 }
 
 bool match_atomic(MatchState&, const type::Type* ty, const type::Type*& T) {
@@ -1092,7 +1093,7 @@
                           const Source& source,
                           bool is_compound) override;
 
-    InitOrConv Lookup(InitConvIntrinsic type,
+    CtorOrConv Lookup(CtorConvIntrinsic type,
                       const type::Type* template_arg,
                       utils::VectorRef<const type::Type*> args,
                       sem::EvaluationStage earliest_eval_stage,
@@ -1200,9 +1201,9 @@
     ProgramBuilder& builder;
     Matchers matchers;
     utils::Hashmap<IntrinsicPrototype, sem::Builtin*, 64, IntrinsicPrototype::Hasher> builtins;
-    utils::Hashmap<IntrinsicPrototype, sem::TypeInitializer*, 16, IntrinsicPrototype::Hasher>
-        initializers;
-    utils::Hashmap<IntrinsicPrototype, sem::TypeConversion*, 16, IntrinsicPrototype::Hasher>
+    utils::Hashmap<IntrinsicPrototype, sem::ValueConstructor*, 16, IntrinsicPrototype::Hasher>
+        constructors;
+    utils::Hashmap<IntrinsicPrototype, sem::ValueConversion*, 16, IntrinsicPrototype::Hasher>
         converters;
 };
 
@@ -1275,24 +1276,26 @@
         params.Reserve(match.parameters.Length());
         for (auto& p : match.parameters) {
             params.Push(builder.create<sem::Parameter>(
-                nullptr, static_cast<uint32_t>(params.Length()), p.type, type::AddressSpace::kNone,
-                type::Access::kUndefined, p.usage));
+                nullptr, static_cast<uint32_t>(params.Length()), p.type,
+                builtin::AddressSpace::kUndefined, builtin::Access::kUndefined, p.usage));
         }
         sem::PipelineStageSet supported_stages;
-        if (match.overload->flags.Contains(OverloadFlag::kSupportsVertexPipeline)) {
+        auto& overload = *match.overload;
+        if (overload.flags.Contains(OverloadFlag::kSupportsVertexPipeline)) {
             supported_stages.Add(ast::PipelineStage::kVertex);
         }
-        if (match.overload->flags.Contains(OverloadFlag::kSupportsFragmentPipeline)) {
+        if (overload.flags.Contains(OverloadFlag::kSupportsFragmentPipeline)) {
             supported_stages.Add(ast::PipelineStage::kFragment);
         }
-        if (match.overload->flags.Contains(OverloadFlag::kSupportsComputePipeline)) {
+        if (overload.flags.Contains(OverloadFlag::kSupportsComputePipeline)) {
             supported_stages.Add(ast::PipelineStage::kCompute);
         }
-        auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
-                                                        : sem::EvaluationStage::kRuntime;
-        return builder.create<sem::Builtin>(
-            builtin_type, match.return_type, std::move(params), eval_stage, supported_stages,
-            match.overload->flags.Contains(OverloadFlag::kIsDeprecated));
+        auto eval_stage = overload.const_eval_fn ? sem::EvaluationStage::kConstant
+                                                 : sem::EvaluationStage::kRuntime;
+        return builder.create<sem::Builtin>(builtin_type, match.return_type, std::move(params),
+                                            eval_stage, supported_stages,
+                                            overload.flags.Contains(OverloadFlag::kIsDeprecated),
+                                            overload.flags.Contains(OverloadFlag::kMustUse));
     });
     return Builtin{sem, match.overload->const_eval_fn};
 }
@@ -1422,7 +1425,7 @@
     };
 }
 
-IntrinsicTable::InitOrConv Impl::Lookup(InitConvIntrinsic type,
+IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type,
                                         const type::Type* template_arg,
                                         utils::VectorRef<const type::Type*> args,
                                         sem::EvaluationStage earliest_eval_stage,
@@ -1432,11 +1435,11 @@
     // Generates an error when no overloads match the provided arguments
     auto on_no_match = [&](utils::VectorRef<Candidate> candidates) {
         std::stringstream ss;
-        ss << "no matching initializer for " << CallSignature(builder, name, args, template_arg)
+        ss << "no matching constructor for " << CallSignature(builder, name, args, template_arg)
            << std::endl;
         Candidates ctor, conv;
         for (auto candidate : candidates) {
-            if (candidate.overload->flags.Contains(OverloadFlag::kIsInitializer)) {
+            if (candidate.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
                 ctor.Push(candidate);
             } else {
                 conv.Push(candidate);
@@ -1444,7 +1447,7 @@
         }
         if (!ctor.IsEmpty()) {
             ss << std::endl
-               << ctor.Length() << " candidate initializer" << (ctor.Length() > 1 ? "s:" : ":")
+               << ctor.Length() << " candidate constructor" << (ctor.Length() > 1 ? "s:" : ":")
                << std::endl;
             PrintCandidates(ss, ctor, name);
         }
@@ -1464,40 +1467,40 @@
     }
 
     // Resolve the intrinsic overload
-    auto match = MatchIntrinsic(kInitializersAndConverters[static_cast<size_t>(type)], name, args,
+    auto match = MatchIntrinsic(kConstructorsAndConverters[static_cast<size_t>(type)], name, args,
                                 earliest_eval_stage, templates, on_no_match);
     if (!match.overload) {
         return {};
     }
 
-    // Was this overload a initializer or conversion?
-    if (match.overload->flags.Contains(OverloadFlag::kIsInitializer)) {
+    // Was this overload a constructor or conversion?
+    if (match.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
         utils::Vector<const sem::Parameter*, 8> params;
         params.Reserve(match.parameters.Length());
         for (auto& p : match.parameters) {
             params.Push(builder.create<sem::Parameter>(
-                nullptr, static_cast<uint32_t>(params.Length()), p.type, type::AddressSpace::kNone,
-                type::Access::kUndefined, p.usage));
+                nullptr, static_cast<uint32_t>(params.Length()), p.type,
+                builtin::AddressSpace::kUndefined, builtin::Access::kUndefined, p.usage));
         }
         auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
                                                         : sem::EvaluationStage::kRuntime;
-        auto* target = initializers.GetOrCreate(match, [&]() {
-            return builder.create<sem::TypeInitializer>(match.return_type, std::move(params),
-                                                        eval_stage);
+        auto* target = constructors.GetOrCreate(match, [&]() {
+            return builder.create<sem::ValueConstructor>(match.return_type, std::move(params),
+                                                         eval_stage);
         });
-        return InitOrConv{target, match.overload->const_eval_fn};
+        return CtorOrConv{target, match.overload->const_eval_fn};
     }
 
     // Conversion.
     auto* target = converters.GetOrCreate(match, [&]() {
         auto param = builder.create<sem::Parameter>(
-            nullptr, 0u, match.parameters[0].type, type::AddressSpace::kNone,
-            type::Access::kUndefined, match.parameters[0].usage);
+            nullptr, 0u, match.parameters[0].type, builtin::AddressSpace::kUndefined,
+            builtin::Access::kUndefined, match.parameters[0].usage);
         auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
                                                         : sem::EvaluationStage::kRuntime;
-        return builder.create<sem::TypeConversion>(match.return_type, param, eval_stage);
+        return builder.create<sem::ValueConversion>(match.return_type, param, eval_stage);
     });
-    return InitOrConv{target, match.overload->const_eval_fn};
+    return CtorOrConv{target, match.overload->const_eval_fn};
 }
 
 IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
@@ -1750,8 +1753,8 @@
             // e.g. vec3<T>(vec3<U>) -> vec3<f32>
             print_template_type = true;
         } else if ((overload->num_parameters == 0) &&
-                   overload->flags.Contains(OverloadFlag::kIsInitializer)) {
-            // Print for initializers with no params
+                   overload->flags.Contains(OverloadFlag::kIsConstructor)) {
+            // Print for constructors with no params
             // e.g. vec2<T>() -> vec2<T>
             print_template_type = true;
         }
diff --git a/src/tint/resolver/intrinsic_table.h b/src/tint/resolver/intrinsic_table.h
index c49ed50..515e839 100644
--- a/src/tint/resolver/intrinsic_table.h
+++ b/src/tint/resolver/intrinsic_table.h
@@ -21,7 +21,7 @@
 #include "src/tint/ast/binary_expression.h"
 #include "src/tint/ast/unary_op.h"
 #include "src/tint/resolver/const_eval.h"
-#include "src/tint/resolver/init_conv_intrinsic.h"
+#include "src/tint/resolver/ctor_conv_intrinsic.h"
 #include "src/tint/sem/builtin.h"
 #include "src/tint/utils/vector.h"
 
@@ -72,9 +72,9 @@
         ConstEval::Function const_eval_fn = nullptr;
     };
 
-    /// InitOrConv describes a resolved type initializer or type conversion
-    struct InitOrConv {
-        /// The result type of the type initializer or type conversion
+    /// CtorOrConv describes a resolved value constructor or conversion
+    struct CtorOrConv {
+        /// The result type of the value constructor or conversion
         const sem::CallTarget* target = nullptr;
         /// The constant evaluation function
         ConstEval::Function const_eval_fn = nullptr;
@@ -137,20 +137,20 @@
                                   const Source& source,
                                   bool is_compound) = 0;
 
-    /// Lookup looks for the type initializer or conversion overload for the given
-    /// InitConvIntrinsic.
+    /// Lookup looks for the value constructor or conversion overload for the given
+    /// CtorConvIntrinsic.
     /// @param type the type being constructed or converted
     /// @param template_arg the optional template argument
-    /// @param args the argument types passed to the initializer / conversion call
+    /// @param args the argument types passed to the constructor / conversion call
     /// @param earliest_eval_stage the the earliest evaluation stage that a call to
-    ///        the initializer or conversion can be made. This can alter the overloads considered.
+    ///        the constructor or conversion can be made. This can alter the overloads considered.
     ///        For example, if the earliest evaluation stage is
     ///        `sem::EvaluationStage::kRuntime`, then only overloads with concrete argument types
     ///        will be considered, as all abstract-numerics will have been materialized
     ///        after shader creation time (sem::EvaluationStage::kConstant).
     /// @param source the source of the call
-    /// @return a sem::TypeInitializer, sem::TypeConversion or nullptr if nothing matched
-    virtual InitOrConv Lookup(InitConvIntrinsic type,
+    /// @return a sem::ValueConstructor, sem::ValueConversion or nullptr if nothing matched
+    virtual CtorOrConv Lookup(CtorConvIntrinsic type,
                               const type::Type* template_arg,
                               utils::VectorRef<const type::Type*> args,
                               sem::EvaluationStage earliest_eval_stage,
diff --git a/src/tint/resolver/intrinsic_table.inl b/src/tint/resolver/intrinsic_table.inl
index a8351f5..a4b5e14 100644
--- a/src/tint/resolver/intrinsic_table.inl
+++ b/src/tint/resolver/intrinsic_table.inl
@@ -8377,7 +8377,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[913],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8389,7 +8389,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[632],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8401,7 +8401,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[914],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8413,7 +8413,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[634],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8425,7 +8425,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[915],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8437,7 +8437,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[636],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8449,7 +8449,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[916],
     /* return matcher indices */ &kMatcherIndices[126],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8461,7 +8461,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[638],
     /* return matcher indices */ &kMatcherIndices[126],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8473,7 +8473,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[917],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8485,7 +8485,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[640],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8497,7 +8497,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[918],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8509,7 +8509,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[642],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8521,7 +8521,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[919],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8533,7 +8533,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[920],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8545,7 +8545,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[644],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8557,7 +8557,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[921],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8569,7 +8569,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[646],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8581,7 +8581,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[922],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8593,7 +8593,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[648],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8605,7 +8605,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[923],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8617,7 +8617,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[650],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8629,7 +8629,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[924],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8641,7 +8641,7 @@
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[925],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8653,7 +8653,7 @@
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[926],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8665,7 +8665,7 @@
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[927],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8677,7 +8677,7 @@
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[928],
     /* return matcher indices */ &kMatcherIndices[126],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8689,7 +8689,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[929],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8701,7 +8701,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[501],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8713,7 +8713,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[504],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8725,7 +8725,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[331],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8737,7 +8737,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[335],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8749,7 +8749,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[185],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8761,7 +8761,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[507],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8773,7 +8773,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[339],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8785,7 +8785,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[510],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8797,7 +8797,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[343],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8809,7 +8809,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[513],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8821,7 +8821,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[347],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8833,7 +8833,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[351],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8845,7 +8845,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[190],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8857,7 +8857,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[516],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8869,7 +8869,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[355],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -8881,7 +8881,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -8893,7 +8893,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[979],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -8905,7 +8905,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[980],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecSplat,
   },
   {
@@ -8917,7 +8917,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[427],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitS,
   },
   {
@@ -8929,7 +8929,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[576],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitM,
   },
   {
@@ -8941,7 +8941,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[579],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitM,
   },
   {
@@ -8953,7 +8953,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[582],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitM,
   },
   {
@@ -8965,7 +8965,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[788],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitM,
   },
   {
@@ -8977,7 +8977,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[790],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitM,
   },
   {
@@ -8989,7 +8989,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[792],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitM,
   },
   {
@@ -9001,7 +9001,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[981],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9013,7 +9013,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[982],
     /* return matcher indices */ &kMatcherIndices[174],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9025,7 +9025,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[983],
     /* return matcher indices */ &kMatcherIndices[154],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9037,7 +9037,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[984],
     /* return matcher indices */ &kMatcherIndices[156],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9049,7 +9049,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[985],
     /* return matcher indices */ &kMatcherIndices[176],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9061,7 +9061,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[387],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9073,7 +9073,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[260],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9085,7 +9085,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[265],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9097,7 +9097,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[126],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9109,7 +9109,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[391],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9121,7 +9121,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[270],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9133,7 +9133,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[395],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9145,7 +9145,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[275],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9157,7 +9157,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[399],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9169,7 +9169,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[280],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9181,7 +9181,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[285],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9193,7 +9193,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[132],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9205,7 +9205,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[403],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9217,7 +9217,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[290],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9229,7 +9229,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[303],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9241,7 +9241,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[150],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9253,7 +9253,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[155],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9265,7 +9265,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[72],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9277,7 +9277,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[307],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9289,7 +9289,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[160],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9301,7 +9301,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[495],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9313,7 +9313,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[311],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9325,7 +9325,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[315],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9337,7 +9337,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[165],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9349,7 +9349,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[498],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9361,7 +9361,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[319],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9517,7 +9517,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[106],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -9529,7 +9529,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[972],
     /* return matcher indices */ &kMatcherIndices[106],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -9541,7 +9541,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[973],
     /* return matcher indices */ &kMatcherIndices[106],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecSplat,
   },
   {
@@ -9553,7 +9553,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[573],
     /* return matcher indices */ &kMatcherIndices[106],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitS,
   },
   {
@@ -9565,7 +9565,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[784],
     /* return matcher indices */ &kMatcherIndices[106],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitM,
   },
   {
@@ -9577,7 +9577,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[786],
     /* return matcher indices */ &kMatcherIndices[106],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitM,
   },
   {
@@ -9589,7 +9589,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[974],
     /* return matcher indices */ &kMatcherIndices[138],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9601,7 +9601,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[975],
     /* return matcher indices */ &kMatcherIndices[168],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9613,7 +9613,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[976],
     /* return matcher indices */ &kMatcherIndices[148],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9625,7 +9625,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[977],
     /* return matcher indices */ &kMatcherIndices[126],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9637,7 +9637,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[978],
     /* return matcher indices */ &kMatcherIndices[170],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -9649,7 +9649,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[935],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9661,7 +9661,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[936],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9673,7 +9673,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[937],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9685,7 +9685,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[938],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9697,7 +9697,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[939],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9709,7 +9709,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[940],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9721,7 +9721,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[941],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9733,7 +9733,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[942],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9745,7 +9745,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[943],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9757,7 +9757,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[944],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9769,7 +9769,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[552],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9781,7 +9781,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[555],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9793,7 +9793,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[419],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9805,7 +9805,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[558],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9817,7 +9817,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[561],
     /* return matcher indices */ &kMatcherIndices[134],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9829,7 +9829,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[564],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9841,7 +9841,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[423],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9853,7 +9853,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[567],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9865,7 +9865,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[652],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -9877,7 +9877,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[692],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiply,
   },
   {
@@ -9889,7 +9889,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[694],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiply,
   },
   {
@@ -9901,7 +9901,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[696],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiply,
   },
   {
@@ -9913,7 +9913,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[698],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiply,
   },
   {
@@ -9925,7 +9925,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[700],
     /* return matcher indices */ &kMatcherIndices[14],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiply,
   },
   {
@@ -9937,7 +9937,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[702],
     /* return matcher indices */ &kMatcherIndices[14],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiply,
   },
   {
@@ -9949,7 +9949,7 @@
     /* template numbers */ &kTemplateNumbers[1],
     /* parameters */ &kParameters[704],
     /* return matcher indices */ &kMatcherIndices[100],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiplyMatVec,
   },
   {
@@ -9961,7 +9961,7 @@
     /* template numbers */ &kTemplateNumbers[1],
     /* parameters */ &kParameters[706],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiplyVecMat,
   },
   {
@@ -9973,7 +9973,7 @@
     /* template numbers */ &kTemplateNumbers[0],
     /* parameters */ &kParameters[708],
     /* return matcher indices */ &kMatcherIndices[30],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMultiplyMatMat,
   },
   {
@@ -9985,7 +9985,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[23],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -9997,7 +9997,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[965],
     /* return matcher indices */ &kMatcherIndices[23],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -10009,7 +10009,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[966],
     /* return matcher indices */ &kMatcherIndices[23],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecSplat,
   },
   {
@@ -10021,7 +10021,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[782],
     /* return matcher indices */ &kMatcherIndices[23],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::VecInitS,
   },
   {
@@ -10033,7 +10033,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[967],
     /* return matcher indices */ &kMatcherIndices[112],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10045,7 +10045,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[968],
     /* return matcher indices */ &kMatcherIndices[164],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10057,7 +10057,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[969],
     /* return matcher indices */ &kMatcherIndices[136],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10069,7 +10069,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[970],
     /* return matcher indices */ &kMatcherIndices[120],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10081,7 +10081,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[971],
     /* return matcher indices */ &kMatcherIndices[166],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10093,7 +10093,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[359],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10105,7 +10105,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[195],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10117,7 +10117,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[200],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10129,7 +10129,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[84],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10141,7 +10141,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[363],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10153,7 +10153,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[205],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10165,7 +10165,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[367],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10177,7 +10177,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[210],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10189,7 +10189,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[245],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10201,7 +10201,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[102],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10213,7 +10213,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[108],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10225,7 +10225,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[65],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10237,7 +10237,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[250],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10249,7 +10249,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[114],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10261,7 +10261,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[255],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10273,7 +10273,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[120],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10285,7 +10285,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[323],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10297,7 +10297,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[170],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10309,7 +10309,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[175],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10321,7 +10321,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[78],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10333,7 +10333,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[327],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10345,7 +10345,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[180],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10357,7 +10357,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[371],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10369,7 +10369,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[215],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10381,7 +10381,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[220],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10393,7 +10393,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[90],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10405,7 +10405,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[375],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10417,7 +10417,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[225],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10429,7 +10429,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[379],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10441,7 +10441,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[230],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10453,7 +10453,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[235],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10465,7 +10465,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[96],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10477,7 +10477,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[383],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10489,7 +10489,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[240],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -10501,7 +10501,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[178],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -10513,7 +10513,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[986],
     /* return matcher indices */ &kMatcherIndices[178],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -10525,7 +10525,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[431],
     /* return matcher indices */ &kMatcherIndices[178],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -10537,7 +10537,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[794],
     /* return matcher indices */ &kMatcherIndices[178],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -10549,7 +10549,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[987],
     /* return matcher indices */ &kMatcherIndices[182],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10561,7 +10561,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[988],
     /* return matcher indices */ &kMatcherIndices[180],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10573,7 +10573,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[184],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -10585,7 +10585,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[989],
     /* return matcher indices */ &kMatcherIndices[184],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -10597,7 +10597,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[138],
     /* return matcher indices */ &kMatcherIndices[184],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -10609,7 +10609,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[796],
     /* return matcher indices */ &kMatcherIndices[184],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -10621,7 +10621,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[990],
     /* return matcher indices */ &kMatcherIndices[188],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10633,7 +10633,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[991],
     /* return matcher indices */ &kMatcherIndices[186],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10645,7 +10645,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[190],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -10657,7 +10657,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[992],
     /* return matcher indices */ &kMatcherIndices[190],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -10669,7 +10669,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[49],
     /* return matcher indices */ &kMatcherIndices[190],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -10681,7 +10681,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[798],
     /* return matcher indices */ &kMatcherIndices[190],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -10693,7 +10693,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[993],
     /* return matcher indices */ &kMatcherIndices[194],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10705,7 +10705,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[994],
     /* return matcher indices */ &kMatcherIndices[192],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10717,7 +10717,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[196],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -10729,7 +10729,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[995],
     /* return matcher indices */ &kMatcherIndices[196],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -10741,7 +10741,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[144],
     /* return matcher indices */ &kMatcherIndices[196],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -10753,7 +10753,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[585],
     /* return matcher indices */ &kMatcherIndices[196],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -10765,7 +10765,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[996],
     /* return matcher indices */ &kMatcherIndices[200],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10777,7 +10777,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[997],
     /* return matcher indices */ &kMatcherIndices[198],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10789,7 +10789,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[202],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -10801,7 +10801,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[998],
     /* return matcher indices */ &kMatcherIndices[202],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -10813,7 +10813,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[40],
     /* return matcher indices */ &kMatcherIndices[202],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -10825,7 +10825,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[588],
     /* return matcher indices */ &kMatcherIndices[202],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -10837,7 +10837,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[999],
     /* return matcher indices */ &kMatcherIndices[206],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10849,7 +10849,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1000],
     /* return matcher indices */ &kMatcherIndices[204],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10861,7 +10861,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[208],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -10873,7 +10873,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1001],
     /* return matcher indices */ &kMatcherIndices[208],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -10885,7 +10885,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[16],
     /* return matcher indices */ &kMatcherIndices[208],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -10897,7 +10897,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[591],
     /* return matcher indices */ &kMatcherIndices[208],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -10909,7 +10909,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1002],
     /* return matcher indices */ &kMatcherIndices[212],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10921,7 +10921,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1003],
     /* return matcher indices */ &kMatcherIndices[210],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10933,7 +10933,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[214],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -10945,7 +10945,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[214],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -10957,7 +10957,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[57],
     /* return matcher indices */ &kMatcherIndices[214],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -10969,7 +10969,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[435],
     /* return matcher indices */ &kMatcherIndices[214],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -10981,7 +10981,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1005],
     /* return matcher indices */ &kMatcherIndices[218],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -10993,7 +10993,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1006],
     /* return matcher indices */ &kMatcherIndices[216],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11005,7 +11005,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[220],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -11017,7 +11017,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1007],
     /* return matcher indices */ &kMatcherIndices[220],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -11029,7 +11029,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[28],
     /* return matcher indices */ &kMatcherIndices[220],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -11041,7 +11041,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[439],
     /* return matcher indices */ &kMatcherIndices[220],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -11053,7 +11053,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1008],
     /* return matcher indices */ &kMatcherIndices[224],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11065,7 +11065,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1009],
     /* return matcher indices */ &kMatcherIndices[222],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11077,7 +11077,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[226],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -11089,7 +11089,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1010],
     /* return matcher indices */ &kMatcherIndices[226],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -11101,7 +11101,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[0],
     /* return matcher indices */ &kMatcherIndices[226],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitS,
   },
   {
@@ -11113,7 +11113,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[443],
     /* return matcher indices */ &kMatcherIndices[226],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::MatInitV,
   },
   {
@@ -11125,7 +11125,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1011],
     /* return matcher indices */ &kMatcherIndices[230],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11137,7 +11137,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1012],
     /* return matcher indices */ &kMatcherIndices[228],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11149,7 +11149,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[930],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -11161,7 +11161,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[931],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -11173,7 +11173,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[932],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -11185,7 +11185,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[933],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -11197,7 +11197,7 @@
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[934],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -11209,7 +11209,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[672],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpPlus,
   },
   {
@@ -11221,7 +11221,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[674],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpPlus,
   },
   {
@@ -11233,7 +11233,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[676],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpPlus,
   },
   {
@@ -11245,7 +11245,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[678],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpPlus,
   },
   {
@@ -11257,7 +11257,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[680],
     /* return matcher indices */ &kMatcherIndices[14],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpPlus,
   },
   {
@@ -11269,7 +11269,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[682],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMinus,
   },
   {
@@ -11281,7 +11281,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[684],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMinus,
   },
   {
@@ -11293,7 +11293,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[686],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMinus,
   },
   {
@@ -11305,7 +11305,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[688],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMinus,
   },
   {
@@ -11317,7 +11317,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[690],
     /* return matcher indices */ &kMatcherIndices[14],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpMinus,
   },
   {
@@ -11329,7 +11329,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[710],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpDivide,
   },
   {
@@ -11341,7 +11341,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[712],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpDivide,
   },
   {
@@ -11353,7 +11353,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[714],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpDivide,
   },
   {
@@ -11365,7 +11365,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[716],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpDivide,
   },
   {
@@ -11377,7 +11377,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[718],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpModulo,
   },
   {
@@ -11389,7 +11389,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[720],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpModulo,
   },
   {
@@ -11401,7 +11401,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[722],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpModulo,
   },
   {
@@ -11413,7 +11413,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[724],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpModulo,
   },
   {
@@ -11425,7 +11425,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[730],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpAnd,
   },
   {
@@ -11437,7 +11437,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[732],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpAnd,
   },
   {
@@ -11449,7 +11449,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[734],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpAnd,
   },
   {
@@ -11461,7 +11461,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[736],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpAnd,
   },
   {
@@ -11473,7 +11473,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[738],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpOr,
   },
   {
@@ -11485,7 +11485,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[740],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpOr,
   },
   {
@@ -11497,7 +11497,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[742],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpOr,
   },
   {
@@ -11509,7 +11509,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[744],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpOr,
   },
   {
@@ -11521,7 +11521,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[468],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::mix,
   },
   {
@@ -11533,7 +11533,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[471],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::mix,
   },
   {
@@ -11545,7 +11545,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[474],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::mix,
   },
   {
@@ -11557,7 +11557,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[480],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::select_bool,
   },
   {
@@ -11569,7 +11569,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[483],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::select_bool,
   },
   {
@@ -11581,7 +11581,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[486],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::select_boolvec,
   },
   {
@@ -11593,7 +11593,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[9],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -11605,7 +11605,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[955],
     /* return matcher indices */ &kMatcherIndices[9],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -11617,7 +11617,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[956],
     /* return matcher indices */ &kMatcherIndices[9],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11629,7 +11629,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -11641,7 +11641,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[957],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -11653,7 +11653,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[958],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11665,7 +11665,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -11677,7 +11677,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[959],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -11689,7 +11689,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[960],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11701,7 +11701,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[1],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -11713,7 +11713,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[961],
     /* return matcher indices */ &kMatcherIndices[1],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -11725,7 +11725,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[962],
     /* return matcher indices */ &kMatcherIndices[1],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11737,7 +11737,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1013],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Zero,
   },
   {
@@ -11749,7 +11749,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[963],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsInitializer, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Identity,
   },
   {
@@ -11761,7 +11761,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[964],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::Conv,
   },
   {
@@ -11773,7 +11773,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[800],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::abs,
   },
   {
@@ -11785,7 +11785,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[801],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::abs,
   },
   {
@@ -11797,7 +11797,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[802],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::acos,
   },
   {
@@ -11809,7 +11809,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[803],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::acos,
   },
   {
@@ -11821,7 +11821,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[804],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::acosh,
   },
   {
@@ -11833,7 +11833,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[805],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::acosh,
   },
   {
@@ -11845,7 +11845,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[806],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::all,
   },
   {
@@ -11857,7 +11857,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[807],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::all,
   },
   {
@@ -11869,7 +11869,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[808],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::any,
   },
   {
@@ -11881,7 +11881,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[809],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::any,
   },
   {
@@ -11893,7 +11893,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[811],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::asin,
   },
   {
@@ -11905,7 +11905,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[812],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::asin,
   },
   {
@@ -11917,7 +11917,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[813],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::asinh,
   },
   {
@@ -11929,7 +11929,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[814],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::asinh,
   },
   {
@@ -11941,7 +11941,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[815],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::atan,
   },
   {
@@ -11953,7 +11953,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[816],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::atan,
   },
   {
@@ -11965,7 +11965,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[594],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::atan2,
   },
   {
@@ -11977,7 +11977,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[596],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::atan2,
   },
   {
@@ -11989,7 +11989,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[817],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::atanh,
   },
   {
@@ -12001,7 +12001,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[818],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::atanh,
   },
   {
@@ -12013,7 +12013,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[819],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::ceil,
   },
   {
@@ -12025,7 +12025,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[820],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::ceil,
   },
   {
@@ -12037,7 +12037,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[447],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::clamp,
   },
   {
@@ -12049,7 +12049,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[450],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::clamp,
   },
   {
@@ -12061,7 +12061,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[821],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::cos,
   },
   {
@@ -12073,7 +12073,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[822],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::cos,
   },
   {
@@ -12085,7 +12085,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[823],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::cosh,
   },
   {
@@ -12097,7 +12097,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[824],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::cosh,
   },
   {
@@ -12109,7 +12109,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[825],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::countLeadingZeros,
   },
   {
@@ -12121,7 +12121,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[826],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::countLeadingZeros,
   },
   {
@@ -12133,7 +12133,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[827],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::countOneBits,
   },
   {
@@ -12145,7 +12145,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[828],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::countOneBits,
   },
   {
@@ -12157,7 +12157,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[829],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::countTrailingZeros,
   },
   {
@@ -12169,7 +12169,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[830],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::countTrailingZeros,
   },
   {
@@ -12181,7 +12181,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[831],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::degrees,
   },
   {
@@ -12193,7 +12193,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[832],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::degrees,
   },
   {
@@ -12205,7 +12205,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[600],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::distance,
   },
   {
@@ -12217,7 +12217,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[602],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::distance,
   },
   {
@@ -12229,7 +12229,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[834],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12241,7 +12241,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[835],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12253,7 +12253,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[836],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12265,7 +12265,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[837],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12277,7 +12277,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[838],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12289,7 +12289,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[839],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12301,7 +12301,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[840],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12313,7 +12313,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[841],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12325,7 +12325,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[842],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12337,7 +12337,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[843],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12349,7 +12349,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[844],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12361,7 +12361,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[845],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12373,7 +12373,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[846],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::exp,
   },
   {
@@ -12385,7 +12385,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[847],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::exp,
   },
   {
@@ -12397,7 +12397,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[848],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::exp2,
   },
   {
@@ -12409,7 +12409,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[849],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::exp2,
   },
   {
@@ -12421,7 +12421,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[453],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::extractBits,
   },
   {
@@ -12433,7 +12433,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[456],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::extractBits,
   },
   {
@@ -12445,7 +12445,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[850],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::firstLeadingBit,
   },
   {
@@ -12457,7 +12457,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[851],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::firstLeadingBit,
   },
   {
@@ -12469,7 +12469,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[852],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::firstTrailingBit,
   },
   {
@@ -12481,7 +12481,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[853],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::firstTrailingBit,
   },
   {
@@ -12493,7 +12493,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[854],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::floor,
   },
   {
@@ -12505,7 +12505,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[855],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::floor,
   },
   {
@@ -12517,7 +12517,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[462],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::fma,
   },
   {
@@ -12529,7 +12529,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[465],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::fma,
   },
   {
@@ -12541,7 +12541,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[856],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::fract,
   },
   {
@@ -12553,7 +12553,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[857],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::fract,
   },
   {
@@ -12565,7 +12565,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[858],
     /* return matcher indices */ &kMatcherIndices[108],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::frexp,
   },
   {
@@ -12577,7 +12577,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[859],
     /* return matcher indices */ &kMatcherIndices[43],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::frexp,
   },
   {
@@ -12589,7 +12589,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[860],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12601,7 +12601,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[861],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12613,7 +12613,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[862],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12625,7 +12625,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[863],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12637,7 +12637,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[864],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12649,7 +12649,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[865],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -12661,7 +12661,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[295],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::insertBits,
   },
   {
@@ -12673,7 +12673,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[299],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::insertBits,
   },
   {
@@ -12685,7 +12685,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[866],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::inverseSqrt,
   },
   {
@@ -12697,7 +12697,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[867],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::inverseSqrt,
   },
   {
@@ -12709,7 +12709,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[610],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::ldexp,
   },
   {
@@ -12721,7 +12721,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[612],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::ldexp,
   },
   {
@@ -12733,7 +12733,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[868],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::length,
   },
   {
@@ -12745,7 +12745,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[869],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::length,
   },
   {
@@ -12757,7 +12757,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[870],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::log,
   },
   {
@@ -12769,7 +12769,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[871],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::log,
   },
   {
@@ -12781,7 +12781,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[872],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::log2,
   },
   {
@@ -12793,7 +12793,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[873],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::log2,
   },
   {
@@ -12805,7 +12805,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[614],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::max,
   },
   {
@@ -12817,7 +12817,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[616],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::max,
   },
   {
@@ -12829,7 +12829,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[618],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::min,
   },
   {
@@ -12841,7 +12841,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[620],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::min,
   },
   {
@@ -12853,7 +12853,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[874],
     /* return matcher indices */ &kMatcherIndices[110],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::modf,
   },
   {
@@ -12865,7 +12865,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[875],
     /* return matcher indices */ &kMatcherIndices[49],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::modf,
   },
   {
@@ -12877,7 +12877,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[622],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::pow,
   },
   {
@@ -12889,7 +12889,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[624],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::pow,
   },
   {
@@ -12901,7 +12901,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[882],
     /* return matcher indices */ &kMatcherIndices[42],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::quantizeToF16,
   },
   {
@@ -12913,7 +12913,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[883],
     /* return matcher indices */ &kMatcherIndices[40],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::quantizeToF16,
   },
   {
@@ -12925,7 +12925,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[884],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::radians,
   },
   {
@@ -12937,7 +12937,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[885],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::radians,
   },
   {
@@ -12949,7 +12949,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[886],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::reverseBits,
   },
   {
@@ -12961,7 +12961,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[887],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::reverseBits,
   },
   {
@@ -12973,7 +12973,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[888],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::round,
   },
   {
@@ -12985,7 +12985,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[889],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::round,
   },
   {
@@ -12997,7 +12997,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[890],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::saturate,
   },
   {
@@ -13009,7 +13009,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[891],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::saturate,
   },
   {
@@ -13021,7 +13021,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[892],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::sign,
   },
   {
@@ -13033,7 +13033,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[893],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::sign,
   },
   {
@@ -13045,7 +13045,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[894],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::sin,
   },
   {
@@ -13057,7 +13057,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[895],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::sin,
   },
   {
@@ -13069,7 +13069,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[896],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::sinh,
   },
   {
@@ -13081,7 +13081,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[897],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::sinh,
   },
   {
@@ -13093,7 +13093,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[489],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::smoothstep,
   },
   {
@@ -13105,7 +13105,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[492],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::smoothstep,
   },
   {
@@ -13117,7 +13117,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[898],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::sqrt,
   },
   {
@@ -13129,7 +13129,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[899],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::sqrt,
   },
   {
@@ -13141,7 +13141,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[628],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::step,
   },
   {
@@ -13153,7 +13153,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[630],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::step,
   },
   {
@@ -13165,7 +13165,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[900],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::tan,
   },
   {
@@ -13177,7 +13177,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[901],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::tan,
   },
   {
@@ -13189,7 +13189,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[902],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::tanh,
   },
   {
@@ -13201,7 +13201,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[903],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::tanh,
   },
   {
@@ -13213,7 +13213,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[905],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::trunc,
   },
   {
@@ -13225,7 +13225,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[906],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::trunc,
   },
   {
@@ -13237,7 +13237,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[945],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -13249,7 +13249,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[946],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -13261,7 +13261,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[519],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -13273,7 +13273,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[522],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -13285,7 +13285,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[949],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpNot,
   },
   {
@@ -13297,7 +13297,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[950],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpNot,
   },
   {
@@ -13309,7 +13309,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[951],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpComplement,
   },
   {
@@ -13321,7 +13321,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[952],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpComplement,
   },
   {
@@ -13333,7 +13333,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[953],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpUnaryMinus,
   },
   {
@@ -13345,7 +13345,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[954],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpUnaryMinus,
   },
   {
@@ -13357,7 +13357,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[726],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpXor,
   },
   {
@@ -13369,7 +13369,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[728],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpXor,
   },
   {
@@ -13381,7 +13381,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[750],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpEqual,
   },
   {
@@ -13393,7 +13393,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[752],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpEqual,
   },
   {
@@ -13405,7 +13405,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[754],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpNotEqual,
   },
   {
@@ -13417,7 +13417,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[756],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpNotEqual,
   },
   {
@@ -13429,7 +13429,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[758],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpLessThan,
   },
   {
@@ -13441,7 +13441,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[760],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpLessThan,
   },
   {
@@ -13453,7 +13453,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[762],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpGreaterThan,
   },
   {
@@ -13465,7 +13465,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[764],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpGreaterThan,
   },
   {
@@ -13477,7 +13477,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[766],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpLessThanEqual,
   },
   {
@@ -13489,7 +13489,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[768],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpLessThanEqual,
   },
   {
@@ -13501,7 +13501,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[770],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpGreaterThanEqual,
   },
   {
@@ -13513,7 +13513,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[772],
     /* return matcher indices */ &kMatcherIndices[37],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpGreaterThanEqual,
   },
   {
@@ -13525,7 +13525,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[774],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpShiftLeft,
   },
   {
@@ -13537,7 +13537,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[776],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpShiftLeft,
   },
   {
@@ -13549,7 +13549,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[778],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpShiftRight,
   },
   {
@@ -13561,7 +13561,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[780],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpShiftRight,
   },
   {
@@ -13573,7 +13573,7 @@
     /* template numbers */ &kTemplateNumbers[8],
     /* parameters */ &kParameters[810],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -13585,7 +13585,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[598],
     /* return matcher indices */ &kMatcherIndices[106],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::cross,
   },
   {
@@ -13597,7 +13597,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[833],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::determinant,
   },
   {
@@ -13609,7 +13609,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[604],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::dot,
   },
   {
@@ -13621,7 +13621,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[606],
     /* return matcher indices */ &kMatcherIndices[9],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -13633,7 +13633,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[608],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -13645,7 +13645,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[459],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::faceForward,
   },
   {
@@ -13657,7 +13657,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[876],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::normalize,
   },
   {
@@ -13669,7 +13669,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[877],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::pack2x16float,
   },
   {
@@ -13681,7 +13681,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[878],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::pack2x16snorm,
   },
   {
@@ -13693,7 +13693,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[879],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::pack2x16unorm,
   },
   {
@@ -13705,7 +13705,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[880],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::pack4x8snorm,
   },
   {
@@ -13717,7 +13717,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[881],
     /* return matcher indices */ &kMatcherIndices[105],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::pack4x8unorm,
   },
   {
@@ -13729,7 +13729,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[626],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::reflect,
   },
   {
@@ -13741,7 +13741,7 @@
     /* template numbers */ &kTemplateNumbers[4],
     /* parameters */ &kParameters[477],
     /* return matcher indices */ &kMatcherIndices[34],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::refract,
   },
   {
@@ -13765,7 +13765,7 @@
     /* template numbers */ &kTemplateNumbers[3],
     /* parameters */ &kParameters[904],
     /* return matcher indices */ &kMatcherIndices[18],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::transpose,
   },
   {
@@ -13777,7 +13777,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[907],
     /* return matcher indices */ &kMatcherIndices[112],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::unpack2x16float,
   },
   {
@@ -13789,7 +13789,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[908],
     /* return matcher indices */ &kMatcherIndices[112],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::unpack2x16snorm,
   },
   {
@@ -13801,7 +13801,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[909],
     /* return matcher indices */ &kMatcherIndices[112],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::unpack2x16unorm,
   },
   {
@@ -13813,7 +13813,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[910],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::unpack4x8snorm,
   },
   {
@@ -13825,7 +13825,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[911],
     /* return matcher indices */ &kMatcherIndices[114],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::unpack4x8unorm,
   },
   {
@@ -13849,7 +13849,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[912],
     /* return matcher indices */ &kMatcherIndices[3],
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ nullptr,
   },
   {
@@ -14005,7 +14005,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[746],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpLogicalAnd,
   },
   {
@@ -14017,7 +14017,7 @@
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[748],
     /* return matcher indices */ &kMatcherIndices[39],
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* const eval */ &ConstEval::OpLogicalOr,
   },
 };
@@ -14502,8 +14502,8 @@
   },
   {
     /* [70] */
-    /* fn sin<T : fa_f32_f16>(T) -> T */
-    /* fn sin<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* fn sin<T : fa_f32_f16>(@test_value(1.57079632679) T) -> T */
+    /* fn sin<N : num, T : fa_f32_f16>(@test_value(1.57079632679) vec<N, T>) -> vec<N, T> */
     /* num overloads */ 2,
     /* overloads */ &kOverloads[389],
   },
@@ -15094,53 +15094,53 @@
 constexpr uint8_t kBinaryOperatorShiftLeft = 16;
 constexpr uint8_t kBinaryOperatorShiftRight = 17;
 
-constexpr IntrinsicInfo kInitializersAndConverters[] = {
+constexpr IntrinsicInfo kConstructorsAndConverters[] = {
   {
     /* [0] */
-    /* init i32() -> i32 */
-    /* init i32(i32) -> i32 */
+    /* ctor i32() -> i32 */
+    /* ctor i32(i32) -> i32 */
     /* conv i32<T : scalar_no_i32>(T) -> i32 */
     /* num overloads */ 3,
     /* overloads */ &kOverloads[268],
   },
   {
     /* [1] */
-    /* init u32() -> u32 */
-    /* init u32(u32) -> u32 */
+    /* ctor u32() -> u32 */
+    /* ctor u32(u32) -> u32 */
     /* conv u32<T : scalar_no_u32>(T) -> u32 */
     /* num overloads */ 3,
     /* overloads */ &kOverloads[271],
   },
   {
     /* [2] */
-    /* init f32() -> f32 */
-    /* init f32(f32) -> f32 */
+    /* ctor f32() -> f32 */
+    /* ctor f32(f32) -> f32 */
     /* conv f32<T : scalar_no_f32>(T) -> f32 */
     /* num overloads */ 3,
     /* overloads */ &kOverloads[274],
   },
   {
     /* [3] */
-    /* init f16() -> f16 */
-    /* init f16(f16) -> f16 */
+    /* ctor f16() -> f16 */
+    /* ctor f16(f16) -> f16 */
     /* conv f16<T : scalar_no_f16>(T) -> f16 */
     /* num overloads */ 3,
     /* overloads */ &kOverloads[277],
   },
   {
     /* [4] */
-    /* init bool() -> bool */
-    /* init bool(bool) -> bool */
+    /* ctor bool() -> bool */
+    /* ctor bool(bool) -> bool */
     /* conv bool<T : scalar_no_bool>(T) -> bool */
     /* num overloads */ 3,
     /* overloads */ &kOverloads[280],
   },
   {
     /* [5] */
-    /* init vec2<T : concrete_scalar>() -> vec2<T> */
-    /* init vec2<T : scalar>(vec2<T>) -> vec2<T> */
-    /* init vec2<T : scalar>(T) -> vec2<T> */
-    /* init vec2<T : scalar>(x: T, y: T) -> vec2<T> */
+    /* ctor vec2<T : concrete_scalar>() -> vec2<T> */
+    /* ctor vec2<T : scalar>(vec2<T>) -> vec2<T> */
+    /* ctor vec2<T : scalar>(T) -> vec2<T> */
+    /* ctor vec2<T : scalar>(x: T, y: T) -> vec2<T> */
     /* conv vec2<T : f32, U : scalar_no_f32>(vec2<U>) -> vec2<f32> */
     /* conv vec2<T : f16, U : scalar_no_f16>(vec2<U>) -> vec2<f16> */
     /* conv vec2<T : i32, U : scalar_no_i32>(vec2<U>) -> vec2<i32> */
@@ -15151,12 +15151,12 @@
   },
   {
     /* [6] */
-    /* init vec3<T : concrete_scalar>() -> vec3<T> */
-    /* init vec3<T : scalar>(vec3<T>) -> vec3<T> */
-    /* init vec3<T : scalar>(T) -> vec3<T> */
-    /* init vec3<T : scalar>(x: T, y: T, z: T) -> vec3<T> */
-    /* init vec3<T : scalar>(xy: vec2<T>, z: T) -> vec3<T> */
-    /* init vec3<T : scalar>(x: T, yz: vec2<T>) -> vec3<T> */
+    /* ctor vec3<T : concrete_scalar>() -> vec3<T> */
+    /* ctor vec3<T : scalar>(vec3<T>) -> vec3<T> */
+    /* ctor vec3<T : scalar>(T) -> vec3<T> */
+    /* ctor vec3<T : scalar>(x: T, y: T, z: T) -> vec3<T> */
+    /* ctor vec3<T : scalar>(xy: vec2<T>, z: T) -> vec3<T> */
+    /* ctor vec3<T : scalar>(x: T, yz: vec2<T>) -> vec3<T> */
     /* conv vec3<T : f32, U : scalar_no_f32>(vec3<U>) -> vec3<f32> */
     /* conv vec3<T : f16, U : scalar_no_f16>(vec3<U>) -> vec3<f16> */
     /* conv vec3<T : i32, U : scalar_no_i32>(vec3<U>) -> vec3<i32> */
@@ -15167,16 +15167,16 @@
   },
   {
     /* [7] */
-    /* init vec4<T : concrete_scalar>() -> vec4<T> */
-    /* init vec4<T : scalar>(vec4<T>) -> vec4<T> */
-    /* init vec4<T : scalar>(T) -> vec4<T> */
-    /* init vec4<T : scalar>(x: T, y: T, z: T, w: T) -> vec4<T> */
-    /* init vec4<T : scalar>(xy: vec2<T>, z: T, w: T) -> vec4<T> */
-    /* init vec4<T : scalar>(x: T, yz: vec2<T>, w: T) -> vec4<T> */
-    /* init vec4<T : scalar>(x: T, y: T, zw: vec2<T>) -> vec4<T> */
-    /* init vec4<T : scalar>(xy: vec2<T>, zw: vec2<T>) -> vec4<T> */
-    /* init vec4<T : scalar>(xyz: vec3<T>, w: T) -> vec4<T> */
-    /* init vec4<T : scalar>(x: T, zyw: vec3<T>) -> vec4<T> */
+    /* ctor vec4<T : concrete_scalar>() -> vec4<T> */
+    /* ctor vec4<T : scalar>(vec4<T>) -> vec4<T> */
+    /* ctor vec4<T : scalar>(T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(x: T, y: T, z: T, w: T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(xy: vec2<T>, z: T, w: T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(x: T, yz: vec2<T>, w: T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(x: T, y: T, zw: vec2<T>) -> vec4<T> */
+    /* ctor vec4<T : scalar>(xy: vec2<T>, zw: vec2<T>) -> vec4<T> */
+    /* ctor vec4<T : scalar>(xyz: vec3<T>, w: T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(x: T, zyw: vec3<T>) -> vec4<T> */
     /* conv vec4<T : f32, U : scalar_no_f32>(vec4<U>) -> vec4<f32> */
     /* conv vec4<T : f16, U : scalar_no_f16>(vec4<U>) -> vec4<f16> */
     /* conv vec4<T : i32, U : scalar_no_i32>(vec4<U>) -> vec4<i32> */
@@ -15187,10 +15187,10 @@
   },
   {
     /* [8] */
-    /* init mat2x2<T : f32_f16>() -> mat2x2<T> */
-    /* init mat2x2<T : f32_f16>(mat2x2<T>) -> mat2x2<T> */
-    /* init mat2x2<T : fa_f32_f16>(T, T, T, T) -> mat2x2<T> */
-    /* init mat2x2<T : fa_f32_f16>(vec2<T>, vec2<T>) -> mat2x2<T> */
+    /* ctor mat2x2<T : f32_f16>() -> mat2x2<T> */
+    /* ctor mat2x2<T : f32_f16>(mat2x2<T>) -> mat2x2<T> */
+    /* ctor mat2x2<T : fa_f32_f16>(T, T, T, T) -> mat2x2<T> */
+    /* ctor mat2x2<T : fa_f32_f16>(vec2<T>, vec2<T>) -> mat2x2<T> */
     /* conv mat2x2<T : f16>(mat2x2<f32>) -> mat2x2<f16> */
     /* conv mat2x2<T : f32>(mat2x2<f16>) -> mat2x2<f32> */
     /* num overloads */ 6,
@@ -15198,10 +15198,10 @@
   },
   {
     /* [9] */
-    /* init mat2x3<T : f32_f16>() -> mat2x3<T> */
-    /* init mat2x3<T : f32_f16>(mat2x3<T>) -> mat2x3<T> */
-    /* init mat2x3<T : fa_f32_f16>(T, T, T, T, T, T) -> mat2x3<T> */
-    /* init mat2x3<T : fa_f32_f16>(vec3<T>, vec3<T>) -> mat2x3<T> */
+    /* ctor mat2x3<T : f32_f16>() -> mat2x3<T> */
+    /* ctor mat2x3<T : f32_f16>(mat2x3<T>) -> mat2x3<T> */
+    /* ctor mat2x3<T : fa_f32_f16>(T, T, T, T, T, T) -> mat2x3<T> */
+    /* ctor mat2x3<T : fa_f32_f16>(vec3<T>, vec3<T>) -> mat2x3<T> */
     /* conv mat2x3<T : f16>(mat2x3<f32>) -> mat2x3<f16> */
     /* conv mat2x3<T : f32>(mat2x3<f16>) -> mat2x3<f32> */
     /* num overloads */ 6,
@@ -15209,10 +15209,10 @@
   },
   {
     /* [10] */
-    /* init mat2x4<T : f32_f16>() -> mat2x4<T> */
-    /* init mat2x4<T : f32_f16>(mat2x4<T>) -> mat2x4<T> */
-    /* init mat2x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T) -> mat2x4<T> */
-    /* init mat2x4<T : fa_f32_f16>(vec4<T>, vec4<T>) -> mat2x4<T> */
+    /* ctor mat2x4<T : f32_f16>() -> mat2x4<T> */
+    /* ctor mat2x4<T : f32_f16>(mat2x4<T>) -> mat2x4<T> */
+    /* ctor mat2x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T) -> mat2x4<T> */
+    /* ctor mat2x4<T : fa_f32_f16>(vec4<T>, vec4<T>) -> mat2x4<T> */
     /* conv mat2x4<T : f16>(mat2x4<f32>) -> mat2x4<f16> */
     /* conv mat2x4<T : f32>(mat2x4<f16>) -> mat2x4<f32> */
     /* num overloads */ 6,
@@ -15220,10 +15220,10 @@
   },
   {
     /* [11] */
-    /* init mat3x2<T : f32_f16>() -> mat3x2<T> */
-    /* init mat3x2<T : f32_f16>(mat3x2<T>) -> mat3x2<T> */
-    /* init mat3x2<T : fa_f32_f16>(T, T, T, T, T, T) -> mat3x2<T> */
-    /* init mat3x2<T : fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T> */
+    /* ctor mat3x2<T : f32_f16>() -> mat3x2<T> */
+    /* ctor mat3x2<T : f32_f16>(mat3x2<T>) -> mat3x2<T> */
+    /* ctor mat3x2<T : fa_f32_f16>(T, T, T, T, T, T) -> mat3x2<T> */
+    /* ctor mat3x2<T : fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T> */
     /* conv mat3x2<T : f16>(mat3x2<f32>) -> mat3x2<f16> */
     /* conv mat3x2<T : f32>(mat3x2<f16>) -> mat3x2<f32> */
     /* num overloads */ 6,
@@ -15231,10 +15231,10 @@
   },
   {
     /* [12] */
-    /* init mat3x3<T : f32_f16>() -> mat3x3<T> */
-    /* init mat3x3<T : f32_f16>(mat3x3<T>) -> mat3x3<T> */
-    /* init mat3x3<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T) -> mat3x3<T> */
-    /* init mat3x3<T : fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T> */
+    /* ctor mat3x3<T : f32_f16>() -> mat3x3<T> */
+    /* ctor mat3x3<T : f32_f16>(mat3x3<T>) -> mat3x3<T> */
+    /* ctor mat3x3<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T) -> mat3x3<T> */
+    /* ctor mat3x3<T : fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T> */
     /* conv mat3x3<T : f16>(mat3x3<f32>) -> mat3x3<f16> */
     /* conv mat3x3<T : f32>(mat3x3<f16>) -> mat3x3<f32> */
     /* num overloads */ 6,
@@ -15242,10 +15242,10 @@
   },
   {
     /* [13] */
-    /* init mat3x4<T : f32_f16>() -> mat3x4<T> */
-    /* init mat3x4<T : f32_f16>(mat3x4<T>) -> mat3x4<T> */
-    /* init mat3x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat3x4<T> */
-    /* init mat3x4<T : fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T> */
+    /* ctor mat3x4<T : f32_f16>() -> mat3x4<T> */
+    /* ctor mat3x4<T : f32_f16>(mat3x4<T>) -> mat3x4<T> */
+    /* ctor mat3x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat3x4<T> */
+    /* ctor mat3x4<T : fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T> */
     /* conv mat3x4<T : f16>(mat3x4<f32>) -> mat3x4<f16> */
     /* conv mat3x4<T : f32>(mat3x4<f16>) -> mat3x4<f32> */
     /* num overloads */ 6,
@@ -15253,10 +15253,10 @@
   },
   {
     /* [14] */
-    /* init mat4x2<T : f32_f16>() -> mat4x2<T> */
-    /* init mat4x2<T : f32_f16>(mat4x2<T>) -> mat4x2<T> */
-    /* init mat4x2<T : fa_f32_f16>(T, T, T, T, T, T, T, T) -> mat4x2<T> */
-    /* init mat4x2<T : fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T> */
+    /* ctor mat4x2<T : f32_f16>() -> mat4x2<T> */
+    /* ctor mat4x2<T : f32_f16>(mat4x2<T>) -> mat4x2<T> */
+    /* ctor mat4x2<T : fa_f32_f16>(T, T, T, T, T, T, T, T) -> mat4x2<T> */
+    /* ctor mat4x2<T : fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T> */
     /* conv mat4x2<T : f16>(mat4x2<f32>) -> mat4x2<f16> */
     /* conv mat4x2<T : f32>(mat4x2<f16>) -> mat4x2<f32> */
     /* num overloads */ 6,
@@ -15264,10 +15264,10 @@
   },
   {
     /* [15] */
-    /* init mat4x3<T : f32_f16>() -> mat4x3<T> */
-    /* init mat4x3<T : f32_f16>(mat4x3<T>) -> mat4x3<T> */
-    /* init mat4x3<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x3<T> */
-    /* init mat4x3<T : fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T> */
+    /* ctor mat4x3<T : f32_f16>() -> mat4x3<T> */
+    /* ctor mat4x3<T : f32_f16>(mat4x3<T>) -> mat4x3<T> */
+    /* ctor mat4x3<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x3<T> */
+    /* ctor mat4x3<T : fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T> */
     /* conv mat4x3<T : f16>(mat4x3<f32>) -> mat4x3<f16> */
     /* conv mat4x3<T : f32>(mat4x3<f16>) -> mat4x3<f32> */
     /* num overloads */ 6,
@@ -15275,10 +15275,10 @@
   },
   {
     /* [16] */
-    /* init mat4x4<T : f32_f16>() -> mat4x4<T> */
-    /* init mat4x4<T : f32_f16>(mat4x4<T>) -> mat4x4<T> */
-    /* init mat4x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x4<T> */
-    /* init mat4x4<T : fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T> */
+    /* ctor mat4x4<T : f32_f16>() -> mat4x4<T> */
+    /* ctor mat4x4<T : f32_f16>(mat4x4<T>) -> mat4x4<T> */
+    /* ctor mat4x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x4<T> */
+    /* ctor mat4x4<T : fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T> */
     /* conv mat4x4<T : f16>(mat4x4<f32>) -> mat4x4<f16> */
     /* conv mat4x4<T : f32>(mat4x4<f16>) -> mat4x4<f32> */
     /* num overloads */ 6,
diff --git a/src/tint/resolver/intrinsic_table.inl.tmpl b/src/tint/resolver/intrinsic_table.inl.tmpl
index e8f87b8..92e7e31 100644
--- a/src/tint/resolver/intrinsic_table.inl.tmpl
+++ b/src/tint/resolver/intrinsic_table.inl.tmpl
@@ -104,7 +104,9 @@
 {{-   range $i, $u := $o.CanBeUsedInStage.List -}}
         , OverloadFlag::kSupports{{Title $u}}Pipeline
 {{-   end }}
-{{-   if $o.IsDeprecated}}, OverloadFlag::kIsDeprecated{{end }}),
+{{-   if $o.MustUse}}, OverloadFlag::kMustUse{{end}}
+{{-   if $o.IsDeprecated}}, OverloadFlag::kIsDeprecated{{end -}}
+    ),
     /* const eval */
 {{-   if $o.ConstEvalFunction }} {{template "ConstEvalFn" $o}},
 {{-   else                    }} nullptr,
@@ -160,8 +162,8 @@
 constexpr uint8_t kBinaryOperator{{ template "ExpandName" $o.Name}} = {{$i}};
 {{- end }}
 
-constexpr IntrinsicInfo kInitializersAndConverters[] = {
-{{- range $i, $o := .InitializersAndConverters }}
+constexpr IntrinsicInfo kConstructorsAndConverters[] = {
+{{- range $i, $o := .ConstructorsAndConverters }}
   {
     /* [{{$i}}] */
 {{-   range $o.OverloadDescriptions }}
diff --git a/src/tint/resolver/intrinsic_table_test.cc b/src/tint/resolver/intrinsic_table_test.cc
index c649c46..7f0399d 100644
--- a/src/tint/resolver/intrinsic_table_test.cc
+++ b/src/tint/resolver/intrinsic_table_test.cc
@@ -19,8 +19,8 @@
 #include "gmock/gmock.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/type/atomic.h"
 #include "src/tint/type/depth_multisampled_texture.h"
 #include "src/tint/type/depth_texture.h"
@@ -231,8 +231,8 @@
 TEST_F(IntrinsicTableTest, MatchPointer) {
     auto* i32 = create<type::I32>();
     auto* atomicI32 = create<type::Atomic>(i32);
-    auto* ptr =
-        create<type::Pointer>(atomicI32, type::AddressSpace::kWorkgroup, type::Access::kReadWrite);
+    auto* ptr = create<type::Pointer>(atomicI32, builtin::AddressSpace::kWorkgroup,
+                                      builtin::Access::kReadWrite);
     auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{ptr},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
@@ -256,7 +256,7 @@
     auto* arr =
         create<type::Array>(create<type::U32>(), create<type::RuntimeArrayCount>(), 4u, 4u, 4u, 4u);
     auto* arr_ptr =
-        create<type::Pointer>(arr, type::AddressSpace::kStorage, type::Access::kReadWrite);
+        create<type::Pointer>(arr, builtin::AddressSpace::kStorage, builtin::Access::kReadWrite);
     auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{arr_ptr},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
@@ -414,9 +414,10 @@
     auto* i32 = create<type::I32>();
     auto* vec2_i32 = create<type::Vector>(i32, 2u);
     auto* vec4_f32 = create<type::Vector>(f32, 4u);
-    auto* subtype = type::StorageTexture::SubtypeFor(type::TexelFormat::kR32Float, Types());
-    auto* tex = create<type::StorageTexture>(
-        type::TextureDimension::k2d, type::TexelFormat::kR32Float, type::Access::kWrite, subtype);
+    auto* subtype = type::StorageTexture::SubtypeFor(builtin::TexelFormat::kR32Float, Types());
+    auto* tex =
+        create<type::StorageTexture>(type::TextureDimension::k2d, builtin::TexelFormat::kR32Float,
+                                     builtin::Access::kWrite, subtype);
 
     auto result = table->Lookup(BuiltinType::kTextureStore, utils::Vector{tex, vec2_i32, vec4_f32},
                                 sem::EvaluationStage::kConstant, Source{});
@@ -445,12 +446,12 @@
 
 TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(
-        BuiltinType::kCos,
-        utils::Vector{
-            create<type::Reference>(f32, type::AddressSpace::kFunction, type::Access::kReadWrite),
-        },
-        sem::EvaluationStage::kConstant, Source{});
+    auto result = table->Lookup(BuiltinType::kCos,
+                                utils::Vector{
+                                    create<type::Reference>(f32, builtin::AddressSpace::kFunction,
+                                                            builtin::Access::kReadWrite),
+                                },
+                                sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
     EXPECT_EQ(result.sem->Type(), BuiltinType::kCos);
@@ -548,8 +549,8 @@
 
 TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Builtin_RuntimeEval) {
     auto* af = create<type::AbstractFloat>();
-    auto* bool_ref = create<type::Reference>(create<type::Bool>(), type::AddressSpace::kFunction,
-                                             type::Access::kReadWrite);
+    auto* bool_ref = create<type::Reference>(create<type::Bool>(), builtin::AddressSpace::kFunction,
+                                             builtin::Access::kReadWrite);
     auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{af, af, bool_ref},
                                 sem::EvaluationStage::kRuntime, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
@@ -801,11 +802,11 @@
 TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicit) {
     auto* i32 = create<type::I32>();
     auto* vec3_i32 = create<type::Vector>(i32, 3u);
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{i32, i32, i32},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, utils::Vector{i32, i32, i32},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->ReturnType(), vec3_i32);
-    EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
     ASSERT_EQ(result.target->Parameters().Length(), 3u);
     EXPECT_EQ(result.target->Parameters()[0]->Type(), i32);
     EXPECT_EQ(result.target->Parameters()[1]->Type(), i32);
@@ -816,11 +817,11 @@
 TEST_F(IntrinsicTableTest, MatchTypeInitializerExplicit) {
     auto* i32 = create<type::I32>();
     auto* vec3_i32 = create<type::Vector>(i32, 3u);
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{i32, i32, i32},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, i32, utils::Vector{i32, i32, i32},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->ReturnType(), vec3_i32);
-    EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
     ASSERT_EQ(result.target->Parameters().Length(), 3u);
     EXPECT_EQ(result.target->Parameters()[0]->Type(), i32);
     EXPECT_EQ(result.target->Parameters()[1]->Type(), i32);
@@ -831,13 +832,13 @@
 TEST_F(IntrinsicTableTest, MismatchTypeInitializerImplicit) {
     auto* i32 = create<type::I32>();
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{i32, f32, i32},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, utils::Vector{i32, f32, i32},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_EQ(result.target, nullptr);
     EXPECT_EQ(Diagnostics().str(),
-              R"(12:34 error: no matching initializer for vec3(i32, f32, i32)
+              R"(12:34 error: no matching constructor for vec3(i32, f32, i32)
 
-6 candidate initializers:
+6 candidate constructors:
   vec3(x: T, y: T, z: T) -> vec3<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec3(xy: vec2<T>, z: T) -> vec3<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec3(x: T, yz: vec2<T>) -> vec3<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
@@ -857,13 +858,13 @@
 TEST_F(IntrinsicTableTest, MismatchTypeInitializerExplicit) {
     auto* i32 = create<type::I32>();
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{i32, f32, i32},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, i32, utils::Vector{i32, f32, i32},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_EQ(result.target, nullptr);
     EXPECT_EQ(Diagnostics().str(),
-              R"(12:34 error: no matching initializer for vec3<i32>(i32, f32, i32)
+              R"(12:34 error: no matching constructor for vec3<i32>(i32, f32, i32)
 
-6 candidate initializers:
+6 candidate constructors:
   vec3(x: T, y: T, z: T) -> vec3<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec3(x: T, yz: vec2<T>) -> vec3<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec3(T) -> vec3<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
@@ -883,11 +884,11 @@
 TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicitVecFromVecAbstract) {
     auto* ai = create<type::AbstractInt>();
     auto* vec3_ai = create<type::Vector>(ai, 3u);
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{vec3_ai},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, utils::Vector{vec3_ai},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->ReturnType(), vec3_ai);
-    EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
     ASSERT_EQ(result.target->Parameters().Length(), 1u);
     EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_ai);
     EXPECT_NE(result.const_eval_fn, nullptr);
@@ -899,11 +900,11 @@
     auto* vec2_af = create<type::Vector>(af, 2u);
     auto* mat2x2_af = create<type::Matrix>(vec2_af, 2u);
     auto result =
-        table->Lookup(InitConvIntrinsic::kMat2x2, nullptr, utils::Vector{vec2_ai, vec2_ai},
+        table->Lookup(CtorConvIntrinsic::kMat2x2, nullptr, utils::Vector{vec2_ai, vec2_ai},
                       sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_NE(result.target, nullptr);
     EXPECT_TYPE(result.target->ReturnType(), mat2x2_af);
-    EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
     ASSERT_EQ(result.target->Parameters().Length(), 2u);
     EXPECT_TYPE(result.target->Parameters()[0]->Type(), vec2_af);
     EXPECT_TYPE(result.target->Parameters()[1]->Type(), vec2_af);
@@ -913,12 +914,12 @@
 TEST_F(IntrinsicTableTest, MatchTypeInitializer_ConstantEval) {
     auto* ai = create<type::AbstractInt>();
     auto* vec3_ai = create<type::Vector>(ai, 3u);
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant);
     EXPECT_EQ(result.target->ReturnType(), vec3_ai);
-    EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
     ASSERT_EQ(result.target->Parameters().Length(), 3u);
     EXPECT_EQ(result.target->Parameters()[0]->Type(), ai);
     EXPECT_EQ(result.target->Parameters()[1]->Type(), ai);
@@ -928,14 +929,14 @@
 
 TEST_F(IntrinsicTableTest, MatchTypeInitializer_RuntimeEval) {
     auto* ai = create<type::AbstractInt>();
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai},
                                 sem::EvaluationStage::kRuntime, Source{{12, 34}});
     auto* i32 = create<type::I32>();
     auto* vec3_i32 = create<type::Vector>(i32, 3u);
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant);
     EXPECT_EQ(result.target->ReturnType(), vec3_i32);
-    EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
     ASSERT_EQ(result.target->Parameters().Length(), 3u);
     EXPECT_EQ(result.target->Parameters()[0]->Type(), i32);
     EXPECT_EQ(result.target->Parameters()[1]->Type(), i32);
@@ -948,11 +949,11 @@
     auto* vec3_i32 = create<type::Vector>(i32, 3u);
     auto* f32 = create<type::F32>();
     auto* vec3_f32 = create<type::Vector>(f32, 3u);
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{vec3_f32},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, i32, utils::Vector{vec3_f32},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->ReturnType(), vec3_i32);
-    EXPECT_TRUE(result.target->Is<sem::TypeConversion>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConversion>());
     ASSERT_EQ(result.target->Parameters().Length(), 1u);
     EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_f32);
 }
@@ -961,13 +962,13 @@
     auto* arr =
         create<type::Array>(create<type::U32>(), create<type::RuntimeArrayCount>(), 4u, 4u, 4u, 4u);
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, f32, utils::Vector{arr},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, f32, utils::Vector{arr},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_EQ(result.target, nullptr);
     EXPECT_EQ(Diagnostics().str(),
-              R"(12:34 error: no matching initializer for vec3<f32>(array<u32>)
+              R"(12:34 error: no matching constructor for vec3<f32>(array<u32>)
 
-6 candidate initializers:
+6 candidate constructors:
   vec3(vec3<T>) -> vec3<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec3(T) -> vec3<T>  where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
   vec3<T>() -> vec3<T>  where: T is f32, f16, i32, u32 or bool
@@ -990,13 +991,13 @@
     auto* vec3_ai = create<type::Vector>(ai, 3u);
     auto* f32 = create<type::F32>();
     auto* vec3_f32 = create<type::Vector>(f32, 3u);
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, af, utils::Vector{vec3_ai},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, af, utils::Vector{vec3_ai},
                                 sem::EvaluationStage::kConstant, Source{{12, 34}});
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant);
     // NOTE: Conversions are explicit, so there's no way to have it return abstracts
     EXPECT_EQ(result.target->ReturnType(), vec3_f32);
-    EXPECT_TRUE(result.target->Is<sem::TypeConversion>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConversion>());
     ASSERT_EQ(result.target->Parameters().Length(), 1u);
     EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_ai);
 }
@@ -1007,12 +1008,12 @@
     auto* vec3_ai = create<type::Vector>(ai, 3u);
     auto* vec3_f32 = create<type::Vector>(create<type::F32>(), 3u);
     auto* vec3_i32 = create<type::Vector>(create<type::I32>(), 3u);
-    auto result = table->Lookup(InitConvIntrinsic::kVec3, af, utils::Vector{vec3_ai},
+    auto result = table->Lookup(CtorConvIntrinsic::kVec3, af, utils::Vector{vec3_ai},
                                 sem::EvaluationStage::kRuntime, Source{{12, 34}});
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant);
     EXPECT_EQ(result.target->ReturnType(), vec3_f32);
-    EXPECT_TRUE(result.target->Is<sem::TypeConversion>());
+    EXPECT_TRUE(result.target->Is<sem::ValueConversion>());
     ASSERT_EQ(result.target->Parameters().Length(), 1u);
     EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_i32);
 }
@@ -1034,7 +1035,7 @@
     // The first should win overload resolution.
     auto* ai = create<type::AbstractInt>();
     auto* i32 = create<type::I32>();
-    auto result = table->Lookup(InitConvIntrinsic::kI32, nullptr, utils::Vector{ai},
+    auto result = table->Lookup(CtorConvIntrinsic::kI32, nullptr, utils::Vector{ai},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.target, nullptr);
     EXPECT_EQ(result.target->ReturnType(), i32);
diff --git a/src/tint/resolver/is_host_shareable_test.cc b/src/tint/resolver/is_host_shareable_test.cc
index 8696900..4570d4d 100644
--- a/src/tint/resolver/is_host_shareable_test.cc
+++ b/src/tint/resolver/is_host_shareable_test.cc
@@ -95,8 +95,8 @@
 }
 
 TEST_F(ResolverIsHostShareable, Pointer) {
-    auto* ptr = create<type::Pointer>(create<type::I32>(), type::AddressSpace::kPrivate,
-                                      type::Access::kReadWrite);
+    auto* ptr = create<type::Pointer>(create<type::I32>(), builtin::AddressSpace::kPrivate,
+                                      builtin::Access::kReadWrite);
     EXPECT_FALSE(r()->IsHostShareable(ptr));
 }
 
diff --git a/src/tint/resolver/is_storeable_test.cc b/src/tint/resolver/is_storeable_test.cc
index bfe64c4..43abdbc 100644
--- a/src/tint/resolver/is_storeable_test.cc
+++ b/src/tint/resolver/is_storeable_test.cc
@@ -78,8 +78,8 @@
 }
 
 TEST_F(ResolverIsStorableTest, Pointer) {
-    auto* ptr = create<type::Pointer>(create<type::I32>(), type::AddressSpace::kPrivate,
-                                      type::Access::kReadWrite);
+    auto* ptr = create<type::Pointer>(create<type::I32>(), builtin::AddressSpace::kPrivate,
+                                      builtin::Access::kReadWrite);
     EXPECT_FALSE(r()->IsStorable(ptr));
 }
 
@@ -112,7 +112,7 @@
 TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
     Structure("S", utils::Vector{
                        Member("a", ty.i32()),
-                       Member("b", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+                       Member("b", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
                    });
 
     EXPECT_FALSE(r()->Resolve());
@@ -138,7 +138,7 @@
     auto* non_storable =
         Structure("nonstorable", utils::Vector{
                                      Member("a", ty.i32()),
-                                     Member("b", ty.pointer<i32>(type::AddressSpace::kPrivate)),
+                                     Member("b", ty.pointer<i32>(builtin::AddressSpace::kPrivate)),
                                  });
     Structure("S", utils::Vector{
                        Member("a", ty.i32()),
diff --git a/src/tint/resolver/materialize_test.cc b/src/tint/resolver/materialize_test.cc
index 4824549..839389a 100644
--- a/src/tint/resolver/materialize_test.cc
+++ b/src/tint/resolver/materialize_test.cc
@@ -340,7 +340,7 @@
             WrapInFunction(CallStmt(Call("F", abstract_expr)));
             break;
         case Method::kBuiltinArg:
-            WrapInFunction(CallStmt(Call("min", target_expr(), abstract_expr)));
+            WrapInFunction(Assign(Phony(), Call("min", target_expr(), abstract_expr)));
             break;
         case Method::kReturn:
             Func("F", utils::Empty, target_ty(), utils::Vector{Return(abstract_expr)});
@@ -929,7 +929,7 @@
             break;
         }
         case Method::kIndex: {
-            GlobalVar("arr", ty.array<i32, 4>(), type::AddressSpace::kPrivate);
+            GlobalVar("arr", ty.array<i32, 4>(), builtin::AddressSpace::kPrivate);
             WrapInFunction(IndexAccessor("arr", abstract_expr()));
             break;
         }
diff --git a/src/tint/resolver/override_test.cc b/src/tint/resolver/override_test.cc
index a9518d2..fd0f649 100644
--- a/src/tint/resolver/override_test.cc
+++ b/src/tint/resolver/override_test.cc
@@ -159,7 +159,7 @@
 
 TEST_F(ResolverOverrideTest, TransitiveReferences_ViaPrivateInit) {
     auto* a = Override("a", ty.f32());
-    auto* b = GlobalVar("b", type::AddressSpace::kPrivate, ty.f32(), Mul(2_a, "a"));
+    auto* b = GlobalVar("b", builtin::AddressSpace::kPrivate, ty.f32(), Mul(2_a, "a"));
     Override("unused", ty.f32(), Expr(1_f));
     auto* func = Func("foo", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -208,7 +208,8 @@
 TEST_F(ResolverOverrideTest, TransitiveReferences_ViaArraySize) {
     auto* a = Override("a", ty.i32());
     auto* b = Override("b", ty.i32(), Mul(2_a, "a"));
-    auto* arr = GlobalVar("arr", type::AddressSpace::kWorkgroup, ty.array(ty.i32(), Mul(2_a, "b")));
+    auto* arr =
+        GlobalVar("arr", builtin::AddressSpace::kWorkgroup, ty.array(ty.i32(), Mul(2_a, "b")));
     auto arr_ty = arr->type;
     Override("unused", ty.i32(), Expr(1_a));
     auto* func = Func("foo", utils::Empty, ty.void_(),
@@ -249,7 +250,7 @@
     auto* a = Override("a", ty.i32());
     auto* b = Override("b", ty.i32(), Mul(2_a, "a"));
     Alias("arr_ty", ty.array(ty.i32(), Mul(2_a, "b")));
-    auto* arr = GlobalVar("arr", type::AddressSpace::kWorkgroup, ty("arr_ty"));
+    auto* arr = GlobalVar("arr", builtin::AddressSpace::kWorkgroup, ty("arr_ty"));
     auto arr_ty = arr->type;
     Override("unused", ty.i32(), Expr(1_a));
     auto* func = Func("foo", utils::Empty, ty.void_(),
@@ -295,8 +296,8 @@
     auto* d = Override("d", ty.i32());
     Alias("arr_ty1", ty.array(ty.i32(), Mul("b1", "c1")));
     Alias("arr_ty2", ty.array(ty.i32(), Mul("b2", "c2")));
-    auto* arr1 = GlobalVar("arr1", type::AddressSpace::kWorkgroup, ty("arr_ty1"));
-    auto* arr2 = GlobalVar("arr2", type::AddressSpace::kWorkgroup, ty("arr_ty2"));
+    auto* arr1 = GlobalVar("arr1", builtin::AddressSpace::kWorkgroup, ty("arr_ty1"));
+    auto* arr2 = GlobalVar("arr2", builtin::AddressSpace::kWorkgroup, ty("arr_ty2"));
     Override("unused", ty.i32(), Expr(1_a));
     auto* func1 = Func("foo1", utils::Empty, ty.void_(),
                        utils::Vector{
diff --git a/src/tint/resolver/ptr_ref_test.cc b/src/tint/resolver/ptr_ref_test.cc
index 692bd3b..1e702a5 100644
--- a/src/tint/resolver/ptr_ref_test.cc
+++ b/src/tint/resolver/ptr_ref_test.cc
@@ -39,7 +39,7 @@
 
     ASSERT_TRUE(TypeOf(expr)->Is<type::Pointer>());
     EXPECT_TRUE(TypeOf(expr)->As<type::Pointer>()->StoreType()->Is<type::I32>());
-    EXPECT_EQ(TypeOf(expr)->As<type::Pointer>()->AddressSpace(), type::AddressSpace::kFunction);
+    EXPECT_EQ(TypeOf(expr)->As<type::Pointer>()->AddressSpace(), builtin::AddressSpace::kFunction);
 }
 
 TEST_F(ResolverPtrRefTest, AddressOfThenDeref) {
@@ -68,23 +68,23 @@
 
     auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
     auto* function = Var("f", ty.i32());
-    auto* private_ = GlobalVar("p", ty.i32(), type::AddressSpace::kPrivate);
-    auto* workgroup = GlobalVar("w", ty.i32(), type::AddressSpace::kWorkgroup);
+    auto* private_ = GlobalVar("p", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* workgroup = GlobalVar("w", ty.i32(), builtin::AddressSpace::kWorkgroup);
     auto* uniform =
-        GlobalVar("ub", ty.Of(buf), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+        GlobalVar("ub", ty.Of(buf), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
     auto* storage =
-        GlobalVar("sb", ty.Of(buf), type::AddressSpace::kStorage, Binding(1_a), Group(0_a));
+        GlobalVar("sb", ty.Of(buf), builtin::AddressSpace::kStorage, Binding(1_a), Group(0_a));
 
     auto* function_ptr =
-        Let("f_ptr", ty.pointer(ty.i32(), type::AddressSpace::kFunction), AddressOf(function));
+        Let("f_ptr", ty.pointer(ty.i32(), builtin::AddressSpace::kFunction), AddressOf(function));
     auto* private_ptr =
-        Let("p_ptr", ty.pointer(ty.i32(), type::AddressSpace::kPrivate), AddressOf(private_));
+        Let("p_ptr", ty.pointer(ty.i32(), builtin::AddressSpace::kPrivate), AddressOf(private_));
     auto* workgroup_ptr =
-        Let("w_ptr", ty.pointer(ty.i32(), type::AddressSpace::kWorkgroup), AddressOf(workgroup));
+        Let("w_ptr", ty.pointer(ty.i32(), builtin::AddressSpace::kWorkgroup), AddressOf(workgroup));
     auto* uniform_ptr =
-        Let("ub_ptr", ty.pointer(ty.Of(buf), type::AddressSpace::kUniform), AddressOf(uniform));
+        Let("ub_ptr", ty.pointer(ty.Of(buf), builtin::AddressSpace::kUniform), AddressOf(uniform));
     auto* storage_ptr =
-        Let("sb_ptr", ty.pointer(ty.Of(buf), type::AddressSpace::kStorage), AddressOf(storage));
+        Let("sb_ptr", ty.pointer(ty.Of(buf), builtin::AddressSpace::kStorage), AddressOf(storage));
 
     WrapInFunction(function, function_ptr, private_ptr, workgroup_ptr, uniform_ptr, storage_ptr);
 
@@ -101,11 +101,11 @@
     ASSERT_TRUE(TypeOf(storage_ptr)->Is<type::Pointer>())
         << "storage_ptr is " << TypeOf(storage_ptr)->TypeInfo().name;
 
-    EXPECT_EQ(TypeOf(function_ptr)->As<type::Pointer>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(private_ptr)->As<type::Pointer>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(workgroup_ptr)->As<type::Pointer>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(uniform_ptr)->As<type::Pointer>()->Access(), type::Access::kRead);
-    EXPECT_EQ(TypeOf(storage_ptr)->As<type::Pointer>()->Access(), type::Access::kRead);
+    EXPECT_EQ(TypeOf(function_ptr)->As<type::Pointer>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(private_ptr)->As<type::Pointer>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(workgroup_ptr)->As<type::Pointer>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(uniform_ptr)->As<type::Pointer>()->Access(), builtin::Access::kRead);
+    EXPECT_EQ(TypeOf(storage_ptr)->As<type::Pointer>()->Access(), builtin::Access::kRead);
 }
 
 }  // namespace
diff --git a/src/tint/resolver/ptr_ref_validation_test.cc b/src/tint/resolver/ptr_ref_validation_test.cc
index 9f6f390..d042402 100644
--- a/src/tint/resolver/ptr_ref_validation_test.cc
+++ b/src/tint/resolver/ptr_ref_validation_test.cc
@@ -143,12 +143,12 @@
     // }
     auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
     auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
-    auto* storage = GlobalVar("s", ty.Of(buf), type::AddressSpace::kStorage,
-                              type::Access::kReadWrite, Binding(0_a), Group(0_a));
+    auto* storage = GlobalVar("s", ty.Of(buf), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite, Binding(0_a), Group(0_a));
 
     auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
-    auto* ptr =
-        Let(Source{{12, 34}}, "p", ty.pointer<i32>(type::AddressSpace::kStorage), AddressOf(expr));
+    auto* ptr = Let(Source{{12, 34}}, "p", ty.pointer<i32>(builtin::AddressSpace::kStorage),
+                    AddressOf(expr));
 
     WrapInFunction(ptr);
 
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 8c36ad7..4292438 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -42,6 +42,7 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/ast/while_statement.h"
 #include "src/tint/ast/workgroup_attribute.h"
+#include "src/tint/builtin/builtin.h"
 #include "src/tint/resolver/uniformity.h"
 #include "src/tint/sem/break_if_statement.h"
 #include "src/tint/sem/builtin_enum_expression.h"
@@ -59,16 +60,15 @@
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/switch_statement.h"
-#include "src/tint/sem/type_conversion.h"
 #include "src/tint/sem/type_expression.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/sem/while_statement.h"
 #include "src/tint/type/abstract_float.h"
 #include "src/tint/type/abstract_int.h"
 #include "src/tint/type/array.h"
 #include "src/tint/type/atomic.h"
-#include "src/tint/type/builtin.h"
 #include "src/tint/type/depth_multisampled_texture.h"
 #include "src/tint/type/depth_texture.h"
 #include "src/tint/type/external_texture.h"
@@ -87,9 +87,12 @@
 #include "src/tint/utils/transform.h"
 #include "src/tint/utils/vector.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::type::Access>);
-TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::type::AddressSpace>);
-TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::type::TexelFormat>);
+TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::builtin::Access>);
+TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::builtin::AddressSpace>);
+TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::builtin::BuiltinValue>);
+TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::builtin::InterpolationSampling>);
+TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::builtin::InterpolationType>);
+TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinEnumExpression<tint::builtin::TexelFormat>);
 
 namespace tint::resolver {
 namespace {
@@ -255,12 +258,12 @@
         ty = rhs->Type()->UnwrapRef();  // Implicit load of RHS
     }
 
-    if (rhs && !validator_.VariableInitializer(v, type::AddressSpace::kNone, ty, rhs)) {
+    if (rhs && !validator_.VariableInitializer(v, builtin::AddressSpace::kUndefined, ty, rhs)) {
         return nullptr;
     }
 
-    if (!ApplyAddressSpaceUsageToType(type::AddressSpace::kNone, const_cast<type::Type*>(ty),
-                                      v->source)) {
+    if (!ApplyAddressSpaceUsageToType(builtin::AddressSpace::kUndefined,
+                                      const_cast<type::Type*>(ty), v->source)) {
         AddNote("while instantiating 'let' " + builder_->Symbols().NameFor(v->name->symbol),
                 v->source);
         return nullptr;
@@ -269,13 +272,13 @@
     sem::Variable* sem = nullptr;
     if (is_global) {
         sem = builder_->create<sem::GlobalVariable>(
-            v, ty, sem::EvaluationStage::kRuntime, type::AddressSpace::kNone,
-            type::Access::kUndefined,
+            v, ty, sem::EvaluationStage::kRuntime, builtin::AddressSpace::kUndefined,
+            builtin::Access::kUndefined,
             /* constant_value */ nullptr, sem::BindingPoint{}, std::nullopt);
     } else {
         sem = builder_->create<sem::LocalVariable>(v, ty, sem::EvaluationStage::kRuntime,
-                                                   type::AddressSpace::kNone,
-                                                   type::Access::kUndefined, current_statement_,
+                                                   builtin::AddressSpace::kUndefined,
+                                                   builtin::Access::kUndefined, current_statement_,
                                                    /* constant_value */ nullptr);
     }
 
@@ -318,19 +321,20 @@
         return nullptr;
     }
 
-    if (rhs && !validator_.VariableInitializer(v, type::AddressSpace::kNone, ty, rhs)) {
+    if (rhs && !validator_.VariableInitializer(v, builtin::AddressSpace::kUndefined, ty, rhs)) {
         return nullptr;
     }
 
-    if (!ApplyAddressSpaceUsageToType(type::AddressSpace::kNone, const_cast<type::Type*>(ty),
-                                      v->source)) {
+    if (!ApplyAddressSpaceUsageToType(builtin::AddressSpace::kUndefined,
+                                      const_cast<type::Type*>(ty), v->source)) {
         AddNote("while instantiating 'override' " + builder_->Symbols().NameFor(v->name->symbol),
                 v->source);
         return nullptr;
     }
 
     auto* sem = builder_->create<sem::GlobalVariable>(
-        v, ty, sem::EvaluationStage::kOverride, type::AddressSpace::kNone, type::Access::kUndefined,
+        v, ty, sem::EvaluationStage::kOverride, builtin::AddressSpace::kUndefined,
+        builtin::Access::kUndefined,
         /* constant_value */ nullptr, sem::BindingPoint{}, std::nullopt);
     sem->SetInitializer(rhs);
 
@@ -411,24 +415,25 @@
         ty = rhs->Type();
     }
 
-    if (!validator_.VariableInitializer(c, type::AddressSpace::kNone, ty, rhs)) {
+    if (!validator_.VariableInitializer(c, builtin::AddressSpace::kUndefined, ty, rhs)) {
         return nullptr;
     }
 
-    if (!ApplyAddressSpaceUsageToType(type::AddressSpace::kNone, const_cast<type::Type*>(ty),
-                                      c->source)) {
+    if (!ApplyAddressSpaceUsageToType(builtin::AddressSpace::kUndefined,
+                                      const_cast<type::Type*>(ty), c->source)) {
         AddNote("while instantiating 'const' " + builder_->Symbols().NameFor(c->name->symbol),
                 c->source);
         return nullptr;
     }
 
     const auto value = rhs->ConstantValue();
-    auto* sem = is_global ? static_cast<sem::Variable*>(builder_->create<sem::GlobalVariable>(
-                                c, ty, sem::EvaluationStage::kConstant, type::AddressSpace::kNone,
-                                type::Access::kUndefined, value, sem::BindingPoint{}, std::nullopt))
-                          : static_cast<sem::Variable*>(builder_->create<sem::LocalVariable>(
-                                c, ty, sem::EvaluationStage::kConstant, type::AddressSpace::kNone,
-                                type::Access::kUndefined, current_statement_, value));
+    auto* sem = is_global
+                    ? static_cast<sem::Variable*>(builder_->create<sem::GlobalVariable>(
+                          c, ty, sem::EvaluationStage::kConstant, builtin::AddressSpace::kUndefined,
+                          builtin::Access::kUndefined, value, sem::BindingPoint{}, std::nullopt))
+                    : static_cast<sem::Variable*>(builder_->create<sem::LocalVariable>(
+                          c, ty, sem::EvaluationStage::kConstant, builtin::AddressSpace::kUndefined,
+                          builtin::Access::kUndefined, current_statement_, value));
 
     sem->SetInitializer(rhs);
     builder_->Sem().Add(c, sem);
@@ -471,29 +476,41 @@
         return nullptr;
     }
 
-    auto address_space = var->declared_address_space;
-    if (address_space == type::AddressSpace::kNone) {
+    auto address_space = builtin::AddressSpace::kUndefined;
+    if (var->declared_address_space) {
+        auto expr = AddressSpaceExpression(var->declared_address_space);
+        if (!expr) {
+            return nullptr;
+        }
+        address_space = expr->Value();
+    } else {
         // No declared address space. Infer from usage / type.
         if (!is_global) {
-            address_space = type::AddressSpace::kFunction;
+            address_space = builtin::AddressSpace::kFunction;
         } else if (storage_ty->UnwrapRef()->is_handle()) {
             // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
             // If the store type is a texture type or a sampler type, then the
             // variable declaration must not have a address space attribute. The
             // address space will always be handle.
-            address_space = type::AddressSpace::kHandle;
+            address_space = builtin::AddressSpace::kHandle;
         }
     }
 
-    if (!is_global && address_space != type::AddressSpace::kFunction &&
+    if (!is_global && address_space != builtin::AddressSpace::kFunction &&
         validator_.IsValidationEnabled(var->attributes,
                                        ast::DisabledValidation::kIgnoreAddressSpace)) {
         AddError("function-scope 'var' declaration must use 'function' address space", var->source);
         return nullptr;
     }
 
-    auto access = var->declared_access;
-    if (access == type::Access::kUndefined) {
+    auto access = builtin::Access::kUndefined;
+    if (var->declared_access) {
+        auto expr = AccessExpression(var->declared_access);
+        if (!expr) {
+            return nullptr;
+        }
+        access = expr->Value();
+    } else {
         access = DefaultAccessForAddressSpace(address_space);
     }
 
@@ -597,7 +614,9 @@
     };
 
     for (auto* attr : param->attributes) {
-        Mark(attr);
+        if (!Attribute(attr)) {
+            return nullptr;
+        }
     }
     if (!validator_.NoDuplicateAttributes(param->attributes)) {
         return nullptr;
@@ -608,7 +627,7 @@
         return nullptr;
     }
 
-    if (!ApplyAddressSpaceUsageToType(type::AddressSpace::kNone, ty, param->type->source)) {
+    if (!ApplyAddressSpaceUsageToType(builtin::AddressSpace::kUndefined, ty, param->type->source)) {
         add_note();
         return nullptr;
     }
@@ -659,7 +678,7 @@
     }
 
     auto* sem = builder_->create<sem::Parameter>(
-        param, index, ty, type::AddressSpace::kNone, type::Access::kUndefined,
+        param, index, ty, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
         sem::ParameterUsage::kNone, binding_point, location);
     builder_->Sem().Add(param, sem);
     return sem;
@@ -689,17 +708,17 @@
     return static_cast<uint32_t>(value);
 }
 
-type::Access Resolver::DefaultAccessForAddressSpace(type::AddressSpace address_space) {
+builtin::Access Resolver::DefaultAccessForAddressSpace(builtin::AddressSpace address_space) {
     // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
     switch (address_space) {
-        case type::AddressSpace::kStorage:
-        case type::AddressSpace::kUniform:
-        case type::AddressSpace::kHandle:
-            return type::Access::kRead;
+        case builtin::AddressSpace::kStorage:
+        case builtin::AddressSpace::kUniform:
+        case builtin::AddressSpace::kHandle:
+            return builtin::Access::kRead;
         default:
             break;
     }
-    return type::Access::kReadWrite;
+    return builtin::Access::kReadWrite;
 }
 
 bool Resolver::AllocateOverridableConstantIds() {
@@ -778,7 +797,9 @@
     }
 
     for (auto* attr : v->attributes) {
-        Mark(attr);
+        if (!Attribute(attr)) {
+            return nullptr;
+        }
     }
 
     if (!validator_.NoDuplicateAttributes(v->attributes)) {
@@ -840,11 +861,8 @@
     validator_.DiagnosticFilters().Push();
     TINT_DEFER(validator_.DiagnosticFilters().Pop());
     for (auto* attr : decl->attributes) {
-        Mark(attr);
-        if (auto* dc = attr->As<ast::DiagnosticAttribute>()) {
-            if (!DiagnosticControl(dc->control)) {
-                return nullptr;
-            }
+        if (!Attribute(attr)) {
+            return nullptr;
         }
     }
     if (!validator_.NoDuplicateAttributes(decl->attributes)) {
@@ -907,7 +925,9 @@
     // Determine if the return type has a location
     std::optional<uint32_t> return_location;
     for (auto* attr : decl->return_type_attributes) {
-        Mark(attr);
+        if (!Attribute(attr)) {
+            return nullptr;
+        }
 
         if (auto* loc_attr = attr->As<ast::LocationAttribute>()) {
             auto value = LocationAttribute(loc_attr);
@@ -919,7 +939,7 @@
     }
 
     if (auto* str = return_type->As<sem::Struct>()) {
-        if (!ApplyAddressSpaceUsageToType(type::AddressSpace::kNone, str, decl->source)) {
+        if (!ApplyAddressSpaceUsageToType(builtin::AddressSpace::kUndefined, str, decl->source)) {
             AddNote("while instantiating return type for " +
                         builder_->Symbols().NameFor(decl->name->symbol),
                     decl->source);
@@ -1398,7 +1418,8 @@
 
     for (auto* expr : utils::Reverse(sorted)) {
         auto* sem_expr = Switch(
-            expr, [&](const ast::IndexAccessorExpression* array) { return IndexAccessor(array); },
+            expr,  //
+            [&](const ast::IndexAccessorExpression* array) { return IndexAccessor(array); },
             [&](const ast::BinaryExpression* bin_op) { return Binary(bin_op); },
             [&](const ast::BitcastExpression* bitcast) { return Bitcast(bitcast); },
             [&](const ast::CallExpression* call) { return Call(call); },
@@ -1468,10 +1489,12 @@
 }
 
 sem::TypeExpression* Resolver::TypeExpression(const ast::Expression* expr) {
+    identifier_resolve_hint_ = {expr, "type"};
     return sem_.AsTypeExpression(Expression(expr));
 }
 
 sem::FunctionExpression* Resolver::FunctionExpression(const ast::Expression* expr) {
+    identifier_resolve_hint_ = {expr, "call target"};
     return sem_.AsFunctionExpression(Expression(expr));
 }
 
@@ -1483,20 +1506,43 @@
     return const_cast<type::Type*>(type_expr->Type());
 }
 
-sem::BuiltinEnumExpression<type::AddressSpace>* Resolver::AddressSpaceExpression(
+sem::BuiltinEnumExpression<builtin::AddressSpace>* Resolver::AddressSpaceExpression(
     const ast::Expression* expr) {
+    identifier_resolve_hint_ = {expr, "address space", builtin::kAddressSpaceStrings};
     return sem_.AsAddressSpace(Expression(expr));
 }
 
-sem::BuiltinEnumExpression<type::TexelFormat>* Resolver::TexelFormatExpression(
+sem::BuiltinEnumExpression<builtin::BuiltinValue>* Resolver::BuiltinValueExpression(
     const ast::Expression* expr) {
+    identifier_resolve_hint_ = {expr, "builtin value", builtin::kBuiltinValueStrings};
+    return sem_.AsBuiltinValue(Expression(expr));
+}
+
+sem::BuiltinEnumExpression<builtin::TexelFormat>* Resolver::TexelFormatExpression(
+    const ast::Expression* expr) {
+    identifier_resolve_hint_ = {expr, "texel format", builtin::kTexelFormatStrings};
     return sem_.AsTexelFormat(Expression(expr));
 }
 
-sem::BuiltinEnumExpression<type::Access>* Resolver::AccessExpression(const ast::Expression* expr) {
+sem::BuiltinEnumExpression<builtin::Access>* Resolver::AccessExpression(
+    const ast::Expression* expr) {
+    identifier_resolve_hint_ = {expr, "access", builtin::kAccessStrings};
     return sem_.AsAccess(Expression(expr));
 }
 
+sem::BuiltinEnumExpression<builtin::InterpolationSampling>* Resolver::InterpolationSampling(
+    const ast::Expression* expr) {
+    identifier_resolve_hint_ = {expr, "interpolation sampling",
+                                builtin::kInterpolationSamplingStrings};
+    return sem_.AsInterpolationSampling(Expression(expr));
+}
+
+sem::BuiltinEnumExpression<builtin::InterpolationType>* Resolver::InterpolationType(
+    const ast::Expression* expr) {
+    identifier_resolve_hint_ = {expr, "interpolation type", builtin::kInterpolationTypeStrings};
+    return sem_.AsInterpolationType(Expression(expr));
+}
+
 void Resolver::RegisterStore(const sem::ValueExpression* expr) {
     auto& info = alias_analysis_infos_[current_function_];
     Switch(
@@ -1893,8 +1939,8 @@
     // A CallExpression can resolve to one of:
     // * A function call.
     // * A builtin call.
-    // * A type initializer.
-    // * A type conversion.
+    // * A value constructor.
+    // * A value conversion.
     auto* target = expr->target;
     Mark(target);
 
@@ -1921,42 +1967,41 @@
     bool has_side_effects =
         std::any_of(args.begin(), args.end(), [](auto* e) { return e->HasSideEffects(); });
 
-    // init_or_conv is a helper for building either a sem::TypeInitializer or
-    // sem::TypeConversion call for a InitConvIntrinsic with an optional template argument type.
-    auto init_or_conv = [&](InitConvIntrinsic ty, const type::Type* template_arg) -> sem::Call* {
+    // ctor_or_conv is a helper for building either a sem::ValueConstructor or
+    // sem::ValueConversion call for a CtorConvIntrinsic with an optional template argument type.
+    auto ctor_or_conv = [&](CtorConvIntrinsic ty, const type::Type* template_arg) -> sem::Call* {
         auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type(); });
-        auto ctor_or_conv =
-            intrinsic_table_->Lookup(ty, template_arg, arg_tys, args_stage, expr->source);
-        if (!ctor_or_conv.target) {
+        auto entry = intrinsic_table_->Lookup(ty, template_arg, arg_tys, args_stage, expr->source);
+        if (!entry.target) {
             return nullptr;
         }
-        if (!MaybeMaterializeAndLoadArguments(args, ctor_or_conv.target)) {
+        if (!MaybeMaterializeAndLoadArguments(args, entry.target)) {
             return nullptr;
         }
 
         const constant::Value* value = nullptr;
-        auto stage = sem::EarliestStage(ctor_or_conv.target->Stage(), args_stage);
+        auto stage = sem::EarliestStage(entry.target->Stage(), args_stage);
         if (stage == sem::EvaluationStage::kConstant && skip_const_eval_.Contains(expr)) {
             stage = sem::EvaluationStage::kNotEvaluated;
         }
         if (stage == sem::EvaluationStage::kConstant) {
-            auto const_args = ConvertArguments(args, ctor_or_conv.target);
+            auto const_args = ConvertArguments(args, entry.target);
             if (!const_args) {
                 return nullptr;
             }
-            if (auto r = (const_eval_.*ctor_or_conv.const_eval_fn)(
-                    ctor_or_conv.target->ReturnType(), const_args.Get(), expr->source)) {
+            if (auto r = (const_eval_.*entry.const_eval_fn)(entry.target->ReturnType(),
+                                                            const_args.Get(), expr->source)) {
                 value = r.Get();
             } else {
                 return nullptr;
             }
         }
-        return builder_->create<sem::Call>(expr, ctor_or_conv.target, stage, std::move(args),
+        return builder_->create<sem::Call>(expr, entry.target, stage, std::move(args),
                                            current_statement_, value, has_side_effects);
     };
 
-    // arr_or_str_init is a helper for building a sem::TypeInitializer for an array or structure
-    // initializer call target.
+    // arr_or_str_init is a helper for building a sem::ValueConstructor for an array or structure
+    // constructor call target.
     auto arr_or_str_init = [&](const type::Type* ty,
                                const sem::CallTarget* call_target) -> sem::Call* {
         if (!MaybeMaterializeAndLoadArguments(args, call_target)) {
@@ -1966,7 +2011,7 @@
         auto stage = args_stage;                 // The evaluation stage of the call
         const constant::Value* value = nullptr;  // The constant value for the call
         if (stage == sem::EvaluationStage::kConstant) {
-            if (auto r = const_eval_.ArrayOrStructInit(ty, args)) {
+            if (auto r = const_eval_.ArrayOrStructCtor(ty, args)) {
                 value = r.Get();
             } else {
                 return nullptr;
@@ -1975,7 +2020,7 @@
                 // Constant evaluation failed.
                 // Can happen for expressions that will fail validation (later).
                 // Use the kRuntime EvaluationStage, as kConstant will trigger an assertion in
-                // the sem::ValueExpression initializer, which checks that kConstant is paired
+                // the sem::ValueExpression constructor, which checks that kConstant is paired
                 // with a constant value.
                 stage = sem::EvaluationStage::kRuntime;
             }
@@ -1988,35 +2033,35 @@
     auto ty_init_or_conv = [&](const type::Type* type) {
         return Switch(
             type,  //
-            [&](const type::I32*) { return init_or_conv(InitConvIntrinsic::kI32, nullptr); },
-            [&](const type::U32*) { return init_or_conv(InitConvIntrinsic::kU32, nullptr); },
+            [&](const type::I32*) { return ctor_or_conv(CtorConvIntrinsic::kI32, nullptr); },
+            [&](const type::U32*) { return ctor_or_conv(CtorConvIntrinsic::kU32, nullptr); },
             [&](const type::F16*) {
                 return validator_.CheckF16Enabled(expr->source)
-                           ? init_or_conv(InitConvIntrinsic::kF16, nullptr)
+                           ? ctor_or_conv(CtorConvIntrinsic::kF16, nullptr)
                            : nullptr;
             },
-            [&](const type::F32*) { return init_or_conv(InitConvIntrinsic::kF32, nullptr); },
-            [&](const type::Bool*) { return init_or_conv(InitConvIntrinsic::kBool, nullptr); },
+            [&](const type::F32*) { return ctor_or_conv(CtorConvIntrinsic::kF32, nullptr); },
+            [&](const type::Bool*) { return ctor_or_conv(CtorConvIntrinsic::kBool, nullptr); },
             [&](const type::Vector* v) {
-                return init_or_conv(VectorInitConvIntrinsic(v->Width()), v->type());
+                return ctor_or_conv(VectorCtorConvIntrinsic(v->Width()), v->type());
             },
             [&](const type::Matrix* m) {
-                return init_or_conv(MatrixInitConvIntrinsic(m->columns(), m->rows()), m->type());
+                return ctor_or_conv(MatrixCtorConvIntrinsic(m->columns(), m->rows()), m->type());
             },
             [&](const type::Array* arr) -> sem::Call* {
-                auto* call_target = array_inits_.GetOrCreate(
-                    ArrayInitializerSig{{arr, args.Length(), args_stage}},
-                    [&]() -> sem::TypeInitializer* {
+                auto* call_target = array_ctors_.GetOrCreate(
+                    ArrayConstructorSig{{arr, args.Length(), args_stage}},
+                    [&]() -> sem::ValueConstructor* {
                         auto params = utils::Transform(args, [&](auto, size_t i) {
                             return builder_->create<sem::Parameter>(
-                                nullptr,                    // declaration
-                                static_cast<uint32_t>(i),   // index
-                                arr->ElemType(),            // type
-                                type::AddressSpace::kNone,  // address_space
-                                type::Access::kUndefined);
+                                nullptr,                            // declaration
+                                static_cast<uint32_t>(i),           // index
+                                arr->ElemType(),                    // type
+                                builtin::AddressSpace::kUndefined,  // address_space
+                                builtin::Access::kUndefined);
                         });
-                        return builder_->create<sem::TypeInitializer>(arr, std::move(params),
-                                                                      args_stage);
+                        return builder_->create<sem::ValueConstructor>(arr, std::move(params),
+                                                                       args_stage);
                     });
 
                 auto* call = arr_or_str_init(arr, call_target);
@@ -2025,27 +2070,27 @@
                 }
 
                 // Validation must occur after argument materialization in arr_or_str_init().
-                if (!validator_.ArrayInitializer(expr, arr)) {
+                if (!validator_.ArrayConstructor(expr, arr)) {
                     return nullptr;
                 }
                 return call;
             },
             [&](const sem::Struct* str) -> sem::Call* {
-                auto* call_target = struct_inits_.GetOrCreate(
-                    StructInitializerSig{{str, args.Length(), args_stage}},
-                    [&]() -> sem::TypeInitializer* {
+                auto* call_target = struct_ctors_.GetOrCreate(
+                    StructConstructorSig{{str, args.Length(), args_stage}},
+                    [&]() -> sem::ValueConstructor* {
                         utils::Vector<const sem::Parameter*, 8> params;
                         params.Resize(std::min(args.Length(), str->Members().Length()));
                         for (size_t i = 0, n = params.Length(); i < n; i++) {
                             params[i] = builder_->create<sem::Parameter>(
-                                nullptr,                    // declaration
-                                static_cast<uint32_t>(i),   // index
-                                str->Members()[i]->Type(),  // type
-                                type::AddressSpace::kNone,  // address_space
-                                type::Access::kUndefined);  // access
+                                nullptr,                            // declaration
+                                static_cast<uint32_t>(i),           // index
+                                str->Members()[i]->Type(),          // type
+                                builtin::AddressSpace::kUndefined,  // address_space
+                                builtin::Access::kUndefined);       // access
                         }
-                        return builder_->create<sem::TypeInitializer>(str, std::move(params),
-                                                                      args_stage);
+                        return builder_->create<sem::ValueConstructor>(str, std::move(params),
+                                                                       args_stage);
                     });
 
                 auto* call = arr_or_str_init(str, call_target);
@@ -2071,7 +2116,7 @@
         auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type()->UnwrapRef(); });
         auto el_ty = type::Type::Common(arg_tys);
         if (!el_ty) {
-            AddError("cannot infer common array element type from initializer arguments",
+            AddError("cannot infer common array element type from constructor arguments",
                      expr->source);
             utils::Hashset<const type::Type*, 8> types;
             for (size_t i = 0; i < args.Length(); i++) {
@@ -2118,37 +2163,37 @@
             return BuiltinCall(expr, f, args);
         }
 
-        if (auto b = resolved->BuiltinType(); b != type::Builtin::kUndefined) {
+        if (auto b = resolved->BuiltinType(); b != builtin::Builtin::kUndefined) {
             if (!ident->Is<ast::TemplatedIdentifier>()) {
                 // No template arguments provided.
                 // Check to see if this is an inferred-element-type call.
                 switch (b) {
-                    case type::Builtin::kArray:
+                    case builtin::Builtin::kArray:
                         return inferred_array();
-                    case type::Builtin::kVec2:
-                        return init_or_conv(InitConvIntrinsic::kVec2, nullptr);
-                    case type::Builtin::kVec3:
-                        return init_or_conv(InitConvIntrinsic::kVec3, nullptr);
-                    case type::Builtin::kVec4:
-                        return init_or_conv(InitConvIntrinsic::kVec4, nullptr);
-                    case type::Builtin::kMat2X2:
-                        return init_or_conv(InitConvIntrinsic::kMat2x2, nullptr);
-                    case type::Builtin::kMat2X3:
-                        return init_or_conv(InitConvIntrinsic::kMat2x3, nullptr);
-                    case type::Builtin::kMat2X4:
-                        return init_or_conv(InitConvIntrinsic::kMat2x4, nullptr);
-                    case type::Builtin::kMat3X2:
-                        return init_or_conv(InitConvIntrinsic::kMat3x2, nullptr);
-                    case type::Builtin::kMat3X3:
-                        return init_or_conv(InitConvIntrinsic::kMat3x3, nullptr);
-                    case type::Builtin::kMat3X4:
-                        return init_or_conv(InitConvIntrinsic::kMat3x4, nullptr);
-                    case type::Builtin::kMat4X2:
-                        return init_or_conv(InitConvIntrinsic::kMat4x2, nullptr);
-                    case type::Builtin::kMat4X3:
-                        return init_or_conv(InitConvIntrinsic::kMat4x3, nullptr);
-                    case type::Builtin::kMat4X4:
-                        return init_or_conv(InitConvIntrinsic::kMat4x4, nullptr);
+                    case builtin::Builtin::kVec2:
+                        return ctor_or_conv(CtorConvIntrinsic::kVec2, nullptr);
+                    case builtin::Builtin::kVec3:
+                        return ctor_or_conv(CtorConvIntrinsic::kVec3, nullptr);
+                    case builtin::Builtin::kVec4:
+                        return ctor_or_conv(CtorConvIntrinsic::kVec4, nullptr);
+                    case builtin::Builtin::kMat2X2:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat2x2, nullptr);
+                    case builtin::Builtin::kMat2X3:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat2x3, nullptr);
+                    case builtin::Builtin::kMat2X4:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat2x4, nullptr);
+                    case builtin::Builtin::kMat3X2:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat3x2, nullptr);
+                    case builtin::Builtin::kMat3X3:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat3x3, nullptr);
+                    case builtin::Builtin::kMat3X4:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat3x4, nullptr);
+                    case builtin::Builtin::kMat4X2:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat4x2, nullptr);
+                    case builtin::Builtin::kMat4X3:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat4x3, nullptr);
+                    case builtin::Builtin::kMat4X4:
+                        return ctor_or_conv(CtorConvIntrinsic::kMat4x4, nullptr);
                     default:
                         break;
                 }
@@ -2160,6 +2205,11 @@
             return ty_init_or_conv(ty);
         }
 
+        if (auto* unresolved = resolved->Unresolved()) {
+            AddError("unresolved call target '" + unresolved->name + "'", expr->source);
+            return nullptr;
+        }
+
         ErrorMismatchedResolvedIdentifier(ident->source, *resolved, "call target");
         return nullptr;
     }();
@@ -2168,7 +2218,7 @@
         return nullptr;
     }
 
-    if (call->Target()->IsAnyOf<sem::TypeInitializer, sem::TypeConversion>()) {
+    if (call->Target()->IsAnyOf<sem::ValueConstructor, sem::ValueConversion>()) {
         // The target of the call was a type.
         // Associate the target identifier expression with the resolved type.
         auto* ty_expr =
@@ -2269,7 +2319,7 @@
     return call;
 }
 
-type::Type* Resolver::BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) {
+type::Type* Resolver::BuiltinType(builtin::Builtin builtin_ty, const ast::Identifier* ident) {
     auto& b = *builder_;
 
     auto check_no_tmpl_args = [&](type::Type* ty) -> type::Type* {
@@ -2505,11 +2555,11 @@
             return nullptr;
         }
 
-        auto* format = sem_.AsTexelFormat(Expression(tmpl_ident->arguments[0]));
+        auto* format = TexelFormatExpression(tmpl_ident->arguments[0]);
         if (TINT_UNLIKELY(!format)) {
             return nullptr;
         }
-        auto* access = sem_.AsAccess(Expression(tmpl_ident->arguments[1]));
+        auto* access = AccessExpression(tmpl_ident->arguments[1]);
         if (TINT_UNLIKELY(!access)) {
             return nullptr;
         }
@@ -2522,151 +2572,151 @@
     };
 
     switch (builtin_ty) {
-        case type::Builtin::kBool:
+        case builtin::Builtin::kBool:
             return check_no_tmpl_args(b.create<type::Bool>());
-        case type::Builtin::kI32:
+        case builtin::Builtin::kI32:
             return check_no_tmpl_args(i32());
-        case type::Builtin::kU32:
+        case builtin::Builtin::kU32:
             return check_no_tmpl_args(u32());
-        case type::Builtin::kF16:
+        case builtin::Builtin::kF16:
             return check_no_tmpl_args(f16());
-        case type::Builtin::kF32:
+        case builtin::Builtin::kF32:
             return check_no_tmpl_args(b.create<type::F32>());
-        case type::Builtin::kVec2:
+        case builtin::Builtin::kVec2:
             return vec_t(2);
-        case type::Builtin::kVec3:
+        case builtin::Builtin::kVec3:
             return vec_t(3);
-        case type::Builtin::kVec4:
+        case builtin::Builtin::kVec4:
             return vec_t(4);
-        case type::Builtin::kMat2X2:
+        case builtin::Builtin::kMat2X2:
             return mat_t(2, 2);
-        case type::Builtin::kMat2X3:
+        case builtin::Builtin::kMat2X3:
             return mat_t(2, 3);
-        case type::Builtin::kMat2X4:
+        case builtin::Builtin::kMat2X4:
             return mat_t(2, 4);
-        case type::Builtin::kMat3X2:
+        case builtin::Builtin::kMat3X2:
             return mat_t(3, 2);
-        case type::Builtin::kMat3X3:
+        case builtin::Builtin::kMat3X3:
             return mat_t(3, 3);
-        case type::Builtin::kMat3X4:
+        case builtin::Builtin::kMat3X4:
             return mat_t(3, 4);
-        case type::Builtin::kMat4X2:
+        case builtin::Builtin::kMat4X2:
             return mat_t(4, 2);
-        case type::Builtin::kMat4X3:
+        case builtin::Builtin::kMat4X3:
             return mat_t(4, 3);
-        case type::Builtin::kMat4X4:
+        case builtin::Builtin::kMat4X4:
             return mat_t(4, 4);
-        case type::Builtin::kMat2X2F:
+        case builtin::Builtin::kMat2X2F:
             return check_no_tmpl_args(mat(f32(), 2u, 2u));
-        case type::Builtin::kMat2X3F:
+        case builtin::Builtin::kMat2X3F:
             return check_no_tmpl_args(mat(f32(), 2u, 3u));
-        case type::Builtin::kMat2X4F:
+        case builtin::Builtin::kMat2X4F:
             return check_no_tmpl_args(mat(f32(), 2u, 4u));
-        case type::Builtin::kMat3X2F:
+        case builtin::Builtin::kMat3X2F:
             return check_no_tmpl_args(mat(f32(), 3u, 2u));
-        case type::Builtin::kMat3X3F:
+        case builtin::Builtin::kMat3X3F:
             return check_no_tmpl_args(mat(f32(), 3u, 3u));
-        case type::Builtin::kMat3X4F:
+        case builtin::Builtin::kMat3X4F:
             return check_no_tmpl_args(mat(f32(), 3u, 4u));
-        case type::Builtin::kMat4X2F:
+        case builtin::Builtin::kMat4X2F:
             return check_no_tmpl_args(mat(f32(), 4u, 2u));
-        case type::Builtin::kMat4X3F:
+        case builtin::Builtin::kMat4X3F:
             return check_no_tmpl_args(mat(f32(), 4u, 3u));
-        case type::Builtin::kMat4X4F:
+        case builtin::Builtin::kMat4X4F:
             return check_no_tmpl_args(mat(f32(), 4u, 4u));
-        case type::Builtin::kMat2X2H:
+        case builtin::Builtin::kMat2X2H:
             return check_no_tmpl_args(mat(f16(), 2u, 2u));
-        case type::Builtin::kMat2X3H:
+        case builtin::Builtin::kMat2X3H:
             return check_no_tmpl_args(mat(f16(), 2u, 3u));
-        case type::Builtin::kMat2X4H:
+        case builtin::Builtin::kMat2X4H:
             return check_no_tmpl_args(mat(f16(), 2u, 4u));
-        case type::Builtin::kMat3X2H:
+        case builtin::Builtin::kMat3X2H:
             return check_no_tmpl_args(mat(f16(), 3u, 2u));
-        case type::Builtin::kMat3X3H:
+        case builtin::Builtin::kMat3X3H:
             return check_no_tmpl_args(mat(f16(), 3u, 3u));
-        case type::Builtin::kMat3X4H:
+        case builtin::Builtin::kMat3X4H:
             return check_no_tmpl_args(mat(f16(), 3u, 4u));
-        case type::Builtin::kMat4X2H:
+        case builtin::Builtin::kMat4X2H:
             return check_no_tmpl_args(mat(f16(), 4u, 2u));
-        case type::Builtin::kMat4X3H:
+        case builtin::Builtin::kMat4X3H:
             return check_no_tmpl_args(mat(f16(), 4u, 3u));
-        case type::Builtin::kMat4X4H:
+        case builtin::Builtin::kMat4X4H:
             return check_no_tmpl_args(mat(f16(), 4u, 4u));
-        case type::Builtin::kVec2F:
+        case builtin::Builtin::kVec2F:
             return check_no_tmpl_args(vec(f32(), 2u));
-        case type::Builtin::kVec3F:
+        case builtin::Builtin::kVec3F:
             return check_no_tmpl_args(vec(f32(), 3u));
-        case type::Builtin::kVec4F:
+        case builtin::Builtin::kVec4F:
             return check_no_tmpl_args(vec(f32(), 4u));
-        case type::Builtin::kVec2H:
+        case builtin::Builtin::kVec2H:
             return check_no_tmpl_args(vec(f16(), 2u));
-        case type::Builtin::kVec3H:
+        case builtin::Builtin::kVec3H:
             return check_no_tmpl_args(vec(f16(), 3u));
-        case type::Builtin::kVec4H:
+        case builtin::Builtin::kVec4H:
             return check_no_tmpl_args(vec(f16(), 4u));
-        case type::Builtin::kVec2I:
+        case builtin::Builtin::kVec2I:
             return check_no_tmpl_args(vec(i32(), 2u));
-        case type::Builtin::kVec3I:
+        case builtin::Builtin::kVec3I:
             return check_no_tmpl_args(vec(i32(), 3u));
-        case type::Builtin::kVec4I:
+        case builtin::Builtin::kVec4I:
             return check_no_tmpl_args(vec(i32(), 4u));
-        case type::Builtin::kVec2U:
+        case builtin::Builtin::kVec2U:
             return check_no_tmpl_args(vec(u32(), 2u));
-        case type::Builtin::kVec3U:
+        case builtin::Builtin::kVec3U:
             return check_no_tmpl_args(vec(u32(), 3u));
-        case type::Builtin::kVec4U:
+        case builtin::Builtin::kVec4U:
             return check_no_tmpl_args(vec(u32(), 4u));
-        case type::Builtin::kArray:
+        case builtin::Builtin::kArray:
             return array();
-        case type::Builtin::kAtomic:
+        case builtin::Builtin::kAtomic:
             return atomic();
-        case type::Builtin::kPtr:
+        case builtin::Builtin::kPtr:
             return ptr();
-        case type::Builtin::kSampler:
+        case builtin::Builtin::kSampler:
             return check_no_tmpl_args(builder_->create<type::Sampler>(type::SamplerKind::kSampler));
-        case type::Builtin::kSamplerComparison:
+        case builtin::Builtin::kSamplerComparison:
             return check_no_tmpl_args(
                 builder_->create<type::Sampler>(type::SamplerKind::kComparisonSampler));
-        case type::Builtin::kTexture1D:
+        case builtin::Builtin::kTexture1D:
             return sampled_texture(type::TextureDimension::k1d);
-        case type::Builtin::kTexture2D:
+        case builtin::Builtin::kTexture2D:
             return sampled_texture(type::TextureDimension::k2d);
-        case type::Builtin::kTexture2DArray:
+        case builtin::Builtin::kTexture2DArray:
             return sampled_texture(type::TextureDimension::k2dArray);
-        case type::Builtin::kTexture3D:
+        case builtin::Builtin::kTexture3D:
             return sampled_texture(type::TextureDimension::k3d);
-        case type::Builtin::kTextureCube:
+        case builtin::Builtin::kTextureCube:
             return sampled_texture(type::TextureDimension::kCube);
-        case type::Builtin::kTextureCubeArray:
+        case builtin::Builtin::kTextureCubeArray:
             return sampled_texture(type::TextureDimension::kCubeArray);
-        case type::Builtin::kTextureDepth2D:
+        case builtin::Builtin::kTextureDepth2D:
             return check_no_tmpl_args(
                 builder_->create<type::DepthTexture>(type::TextureDimension::k2d));
-        case type::Builtin::kTextureDepth2DArray:
+        case builtin::Builtin::kTextureDepth2DArray:
             return check_no_tmpl_args(
                 builder_->create<type::DepthTexture>(type::TextureDimension::k2dArray));
-        case type::Builtin::kTextureDepthCube:
+        case builtin::Builtin::kTextureDepthCube:
             return check_no_tmpl_args(
                 builder_->create<type::DepthTexture>(type::TextureDimension::kCube));
-        case type::Builtin::kTextureDepthCubeArray:
+        case builtin::Builtin::kTextureDepthCubeArray:
             return check_no_tmpl_args(
                 builder_->create<type::DepthTexture>(type::TextureDimension::kCubeArray));
-        case type::Builtin::kTextureDepthMultisampled2D:
+        case builtin::Builtin::kTextureDepthMultisampled2D:
             return check_no_tmpl_args(
                 builder_->create<type::DepthMultisampledTexture>(type::TextureDimension::k2d));
-        case type::Builtin::kTextureExternal:
+        case builtin::Builtin::kTextureExternal:
             return check_no_tmpl_args(builder_->create<type::ExternalTexture>());
-        case type::Builtin::kTextureMultisampled2D:
+        case builtin::Builtin::kTextureMultisampled2D:
             return multisampled_texture(type::TextureDimension::k2d);
-        case type::Builtin::kTextureStorage1D:
+        case builtin::Builtin::kTextureStorage1D:
             return storage_texture(type::TextureDimension::k1d);
-        case type::Builtin::kTextureStorage2D:
+        case builtin::Builtin::kTextureStorage2D:
             return storage_texture(type::TextureDimension::k2d);
-        case type::Builtin::kTextureStorage2DArray:
+        case builtin::Builtin::kTextureStorage2DArray:
             return storage_texture(type::TextureDimension::k2dArray);
-        case type::Builtin::kTextureStorage3D:
+        case builtin::Builtin::kTextureStorage3D:
             return storage_texture(type::TextureDimension::k3d);
-        case type::Builtin::kUndefined:
+        case builtin::Builtin::kUndefined:
             break;
     }
 
@@ -2949,7 +2999,7 @@
             });
     }
 
-    if (auto builtin_ty = resolved->BuiltinType(); builtin_ty != type::Builtin::kUndefined) {
+    if (auto builtin_ty = resolved->BuiltinType(); builtin_ty != builtin::Builtin::kUndefined) {
         auto* ty = BuiltinType(builtin_ty, ident);
         if (!ty) {
             return nullptr;
@@ -2962,21 +3012,62 @@
         return nullptr;
     }
 
-    if (auto access = resolved->Access(); access != type::Access::kUndefined) {
-        return builder_->create<sem::BuiltinEnumExpression<type::Access>>(expr, current_statement_,
-                                                                          access);
+    if (auto access = resolved->Access(); access != builtin::Access::kUndefined) {
+        return builder_->create<sem::BuiltinEnumExpression<builtin::Access>>(
+            expr, current_statement_, access);
     }
 
-    if (auto addr = resolved->AddressSpace(); addr != type::AddressSpace::kUndefined) {
-        return builder_->create<sem::BuiltinEnumExpression<type::AddressSpace>>(
+    if (auto addr = resolved->AddressSpace(); addr != builtin::AddressSpace::kUndefined) {
+        return builder_->create<sem::BuiltinEnumExpression<builtin::AddressSpace>>(
             expr, current_statement_, addr);
     }
 
-    if (auto fmt = resolved->TexelFormat(); fmt != type::TexelFormat::kUndefined) {
-        return builder_->create<sem::BuiltinEnumExpression<type::TexelFormat>>(
+    if (auto builtin = resolved->BuiltinValue(); builtin != builtin::BuiltinValue::kUndefined) {
+        return builder_->create<sem::BuiltinEnumExpression<builtin::BuiltinValue>>(
+            expr, current_statement_, builtin);
+    }
+
+    if (auto i_smpl = resolved->InterpolationSampling();
+        i_smpl != builtin::InterpolationSampling::kUndefined) {
+        return builder_->create<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
+            expr, current_statement_, i_smpl);
+    }
+
+    if (auto i_type = resolved->InterpolationType();
+        i_type != builtin::InterpolationType::kUndefined) {
+        return builder_->create<sem::BuiltinEnumExpression<builtin::InterpolationType>>(
+            expr, current_statement_, i_type);
+    }
+
+    if (auto fmt = resolved->TexelFormat(); fmt != builtin::TexelFormat::kUndefined) {
+        return builder_->create<sem::BuiltinEnumExpression<builtin::TexelFormat>>(
             expr, current_statement_, fmt);
     }
 
+    if (auto* unresolved = resolved->Unresolved()) {
+        if (identifier_resolve_hint_.expression == expr) {
+            AddError("unresolved " + std::string(identifier_resolve_hint_.usage) + " '" +
+                         unresolved->name + "'",
+                     expr->source);
+            if (!identifier_resolve_hint_.suggestions.IsEmpty()) {
+                // Filter out suggestions that have a leading underscore.
+                utils::Vector<const char*, 8> filtered;
+                for (auto* str : identifier_resolve_hint_.suggestions) {
+                    if (str[0] != '_') {
+                        filtered.Push(str);
+                    }
+                }
+                std::ostringstream msg;
+                utils::SuggestAlternatives(unresolved->name,
+                                           filtered.Slice().Reinterpret<char const* const>(), msg);
+                AddNote(msg.str(), expr->source);
+            }
+        } else {
+            AddError("unresolved identifier '" + unresolved->name + "'", expr->source);
+        }
+        return nullptr;
+    }
+
     TINT_UNREACHABLE(Resolver, diagnostics_)
         << "unhandled resolved identifier: " << resolved->String(builder_->Symbols(), diagnostics_);
     return nullptr;
@@ -3292,17 +3383,48 @@
     return sem;
 }
 
+bool Resolver::Attribute(const ast::Attribute* attr) {
+    Mark(attr);
+    return Switch(
+        attr,  //
+        [&](const ast::BuiltinAttribute* b) { return BuiltinAttribute(b); },
+        [&](const ast::DiagnosticAttribute* d) { return DiagnosticControl(d->control); },
+        [&](const ast::InterpolateAttribute* i) { return InterpolateAttribute(i); },
+        [&](Default) { return true; });
+}
+
+bool Resolver::BuiltinAttribute(const ast::BuiltinAttribute* attr) {
+    auto* builtin_expr = BuiltinValueExpression(attr->builtin);
+    if (!builtin_expr) {
+        return false;
+    }
+    // Apply the resolved tint::sem::BuiltinEnumExpression<tint::builtin::BuiltinValue> to the
+    // attribute.
+    builder_->Sem().Add(attr, builtin_expr);
+    return true;
+}
+
+bool Resolver::InterpolateAttribute(const ast::InterpolateAttribute* attr) {
+    if (!InterpolationType(attr->type)) {
+        return false;
+    }
+    if (attr->sampling && !InterpolationSampling(attr->sampling)) {
+        return false;
+    }
+    return true;
+}
+
 bool Resolver::DiagnosticControl(const ast::DiagnosticControl& control) {
     Mark(control.rule_name);
 
     auto rule_name = builder_->Symbols().NameFor(control.rule_name->symbol);
-    auto rule = ast::ParseDiagnosticRule(rule_name);
-    if (rule != ast::DiagnosticRule::kUndefined) {
+    auto rule = builtin::ParseDiagnosticRule(rule_name);
+    if (rule != builtin::DiagnosticRule::kUndefined) {
         validator_.DiagnosticFilters().Set(rule, control.severity);
     } else {
         std::ostringstream ss;
         ss << "unrecognized diagnostic rule '" << rule_name << "'\n";
-        utils::SuggestAlternatives(rule_name, ast::kDiagnosticRuleStrings, ss);
+        utils::SuggestAlternatives(rule_name, builtin::kDiagnosticRuleStrings, ss);
         AddWarning(ss.str(), control.rule_name->source);
     }
     return true;
@@ -3451,6 +3573,20 @@
 }
 
 sem::Struct* Resolver::Structure(const ast::Struct* str) {
+    if (validator_.IsValidationEnabled(str->attributes,
+                                       ast::DisabledValidation::kIgnoreStructMemberLimit)) {
+        // Maximum number of members in a structure type
+        // https://gpuweb.github.io/gpuweb/wgsl/#limits
+        const size_t kMaxNumStructMembers = 16383;
+        if (str->members.Length() > kMaxNumStructMembers) {
+            AddError("struct '" + builder_->Symbols().NameFor(str->name->symbol) + "' has " +
+                         std::to_string(str->members.Length()) + " members, maximum is " +
+                         std::to_string(kMaxNumStructMembers),
+                     str->source);
+            return nullptr;
+        }
+    }
+
     if (!validator_.NoDuplicateAttributes(str->attributes)) {
         return nullptr;
     }
@@ -3507,7 +3643,9 @@
         bool has_size_attr = false;
         std::optional<uint32_t> location;
         for (auto* attr : member->attributes) {
-            Mark(attr);
+            if (!Attribute(attr)) {
+                return nullptr;
+            }
             bool ok = Switch(
                 attr,  //
                 [&](const ast::StructMemberOffsetAttribute* o) {
@@ -3965,7 +4103,7 @@
     });
 }
 
-bool Resolver::ApplyAddressSpaceUsageToType(type::AddressSpace address_space,
+bool Resolver::ApplyAddressSpaceUsageToType(builtin::AddressSpace address_space,
                                             type::Type* ty,
                                             const Source& usage) {
     ty = const_cast<type::Type*>(ty->UnwrapRef());
@@ -3993,7 +4131,7 @@
     }
 
     if (auto* arr = ty->As<type::Array>()) {
-        if (address_space != type::AddressSpace::kStorage) {
+        if (address_space != builtin::AddressSpace::kStorage) {
             if (arr->Count()->Is<type::RuntimeArrayCount>()) {
                 AddError("runtime-sized arrays can only be used in the <storage> address space",
                          usage);
@@ -4012,7 +4150,7 @@
                                             usage);
     }
 
-    if (type::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) {
+    if (builtin::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) {
         std::stringstream err;
         err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in address space '"
             << address_space << "' as it is non-host-shareable";
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index 003fa3d..72f9e8f 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -67,7 +67,6 @@
 class Statement;
 class StructMember;
 class SwitchStatement;
-class TypeInitializer;
 class WhileStatement;
 }  // namespace tint::sem
 namespace tint::type {
@@ -138,22 +137,44 @@
     /// @returns the resolved type from an expression, or nullptr on error
     type::Type* Type(const ast::Expression* ast);
 
-    /// @returns the call of Expression() cast to a sem::BuiltinEnumExpression<type::AddressSpace>.
-    /// If the sem::Expression is not a sem::BuiltinEnumExpression<type::AddressSpace>, then an
-    /// error diagnostic is raised and nullptr is returned.
-    sem::BuiltinEnumExpression<type::AddressSpace>* AddressSpaceExpression(
+    /// @returns the call of Expression() cast to a
+    /// sem::BuiltinEnumExpression<builtin::AddressSpace>. If the sem::Expression is not a
+    /// sem::BuiltinEnumExpression<builtin::AddressSpace>, then an error diagnostic is raised and
+    /// nullptr is returned.
+    sem::BuiltinEnumExpression<builtin::AddressSpace>* AddressSpaceExpression(
+        const ast::Expression* expr);
+
+    /// @returns the call of Expression() cast to a
+    /// sem::BuiltinEnumExpression<builtin::BuiltinValue>. If the sem::Expression is not a
+    /// sem::BuiltinEnumExpression<builtin::BuiltinValue>, then an error diagnostic is raised and
+    /// nullptr is returned.
+    sem::BuiltinEnumExpression<builtin::BuiltinValue>* BuiltinValueExpression(
         const ast::Expression* expr);
 
     /// @returns the call of Expression() cast to a sem::BuiltinEnumExpression<type::TexelFormat>.
     /// If the sem::Expression is not a sem::BuiltinEnumExpression<type::TexelFormat>, then an error
     /// diagnostic is raised and nullptr is returned.
-    sem::BuiltinEnumExpression<type::TexelFormat>* TexelFormatExpression(
+    sem::BuiltinEnumExpression<builtin::TexelFormat>* TexelFormatExpression(
         const ast::Expression* expr);
 
-    /// @returns the call of Expression() cast to a sem::BuiltinEnumExpression<type::Access>*.
-    /// If the sem::Expression is not a sem::BuiltinEnumExpression<type::Access>*, then an error
+    /// @returns the call of Expression() cast to a sem::BuiltinEnumExpression<builtin::Access>*.
+    /// If the sem::Expression is not a sem::BuiltinEnumExpression<builtin::Access>*, then an error
     /// diagnostic is raised and nullptr is returned.
-    sem::BuiltinEnumExpression<type::Access>* AccessExpression(const ast::Expression* expr);
+    sem::BuiltinEnumExpression<builtin::Access>* AccessExpression(const ast::Expression* expr);
+
+    /// @returns the call of Expression() cast to a
+    /// sem::BuiltinEnumExpression<builtin::InterpolationSampling>*. If the sem::Expression is not a
+    /// sem::BuiltinEnumExpression<builtin::InterpolationSampling>*, then an error diagnostic is
+    /// raised and nullptr is returned.
+    sem::BuiltinEnumExpression<builtin::InterpolationSampling>* InterpolationSampling(
+        const ast::Expression* expr);
+
+    /// @returns the call of Expression() cast to a
+    /// sem::BuiltinEnumExpression<builtin::InterpolationType>*. If the sem::Expression is not a
+    /// sem::BuiltinEnumExpression<builtin::InterpolationType>*, then an error diagnostic is raised
+    /// and nullptr is returned.
+    sem::BuiltinEnumExpression<builtin::InterpolationType>* InterpolationType(
+        const ast::Expression* expr);
 
     /// Expression traverses the graph of expressions starting at `expr`, building a post-ordered
     /// list (leaf-first) of all the expression nodes. Each of the expressions are then resolved by
@@ -288,6 +309,18 @@
     /// current_function_
     bool WorkgroupSize(const ast::Function*);
 
+    /// Resolves the attribute @p attr
+    /// @returns true on success, false on failure
+    bool Attribute(const ast::Attribute* attr);
+
+    /// Resolves the `@builtin` attribute @p attr
+    /// @returns true on success, false on failure
+    bool BuiltinAttribute(const ast::BuiltinAttribute* attr);
+
+    /// Resolves the `@interpolate` attribute @p attr
+    /// @returns true on success, false on failure
+    bool InterpolateAttribute(const ast::InterpolateAttribute* attr);
+
     /// @param control the diagnostic control
     /// @returns true on success, false on failure
     bool DiagnosticControl(const ast::DiagnosticControl& control);
@@ -401,11 +434,13 @@
     /// given type and address space. Used for generating sensible error
     /// messages.
     /// @returns true on success, false on error
-    bool ApplyAddressSpaceUsageToType(type::AddressSpace sc, type::Type* ty, const Source& usage);
+    bool ApplyAddressSpaceUsageToType(builtin::AddressSpace sc,
+                                      type::Type* ty,
+                                      const Source& usage);
 
     /// @param address_space the address space
     /// @returns the default access control for the given address space
-    type::Access DefaultAccessForAddressSpace(type::AddressSpace address_space);
+    builtin::Access DefaultAccessForAddressSpace(builtin::AddressSpace address_space);
 
     /// Allocate constant IDs for pipeline-overridable constants.
     /// @returns true on success, false on error
@@ -459,17 +494,17 @@
 
     /// @returns the type::Type for the builtin type @p builtin_ty with the identifier @p ident
     /// @note: Will raise an ICE if @p symbol is not a builtin type.
-    type::Type* BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident);
+    type::Type* BuiltinType(builtin::Builtin builtin_ty, const ast::Identifier* ident);
 
-    // ArrayInitializerSig represents a unique array initializer signature.
+    // ArrayConstructorSig represents a unique array constructor signature.
     // It is a tuple of the array type, number of arguments provided and earliest evaluation stage.
-    using ArrayInitializerSig =
+    using ArrayConstructorSig =
         utils::UnorderedKeyWrapper<std::tuple<const type::Array*, size_t, sem::EvaluationStage>>;
 
-    // StructInitializerSig represents a unique structure initializer signature.
+    // StructConstructorSig represents a unique structure constructor signature.
     // It is a tuple of the structure type, number of arguments provided and earliest evaluation
     // stage.
-    using StructInitializerSig =
+    using StructConstructorSig =
         utils::UnorderedKeyWrapper<std::tuple<const sem::Struct*, size_t, sem::EvaluationStage>>;
 
     /// ExprEvalStageConstraint describes a constraint on when expressions can be evaluated.
@@ -494,6 +529,17 @@
         std::unordered_set<const sem::Variable*> parameter_reads;
     };
 
+    /// A hint for the usage of an identifier expression.
+    /// Used to provide more informative error diagnostics on resolution failure.
+    struct IdentifierResolveHint {
+        /// The expression this hint applies to
+        const ast::Expression* expression = nullptr;
+        /// The usage of the identifier.
+        const char* usage = "identifier";
+        /// Suggested strings if the identifier failed to resolve
+        utils::Slice<char const* const> suggestions = utils::Empty;
+    };
+
     ProgramBuilder* const builder_;
     diag::List& diagnostics_;
     ConstEval const_eval_;
@@ -508,8 +554,8 @@
     ExprEvalStageConstraint expr_eval_stage_constraint_;
     std::unordered_map<const sem::Function*, AliasAnalysisInfo> alias_analysis_infos_;
     utils::Hashmap<OverrideId, const sem::Variable*, 8> override_ids_;
-    utils::Hashmap<ArrayInitializerSig, sem::CallTarget*, 8> array_inits_;
-    utils::Hashmap<StructInitializerSig, sem::CallTarget*, 8> struct_inits_;
+    utils::Hashmap<ArrayConstructorSig, sem::CallTarget*, 8> array_ctors_;
+    utils::Hashmap<StructConstructorSig, sem::CallTarget*, 8> struct_ctors_;
     sem::Function* current_function_ = nullptr;
     sem::Statement* current_statement_ = nullptr;
     sem::CompoundStatement* current_compound_statement_ = nullptr;
@@ -519,6 +565,7 @@
     utils::Hashmap<const ast::Expression*, const ast::BinaryExpression*, 8>
         logical_binary_lhs_to_parent_;
     utils::Hashset<const ast::Expression*, 8> skip_const_eval_;
+    IdentifierResolveHint identifier_resolve_hint_;
 };
 
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc
index c0d48bc..25155ff 100644
--- a/src/tint/resolver/resolver_test.cc
+++ b/src/tint/resolver/resolver_test.cc
@@ -34,6 +34,7 @@
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/ast/workgroup_attribute.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/function.h"
@@ -325,7 +326,7 @@
 
 TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScope) {
     auto* init = Expr(2_i);
-    GlobalVar("my_var", ty.i32(), type::AddressSpace::kPrivate, init);
+    GlobalVar("my_var", ty.i32(), builtin::AddressSpace::kPrivate, init);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -405,7 +406,7 @@
     Func("func_i32", utils::Empty, ty.void_(), utils::Vector{fn_i32_decl});
 
     // Declare f32 "foo" at module scope
-    auto* mod_f32 = Var("foo", ty.f32(), type::AddressSpace::kPrivate, Expr(2_f));
+    auto* mod_f32 = Var("foo", ty.f32(), builtin::AddressSpace::kPrivate, Expr(2_f));
     auto* mod_init = mod_f32->initializer;
     AST().AddGlobalVariable(mod_f32);
 
@@ -433,7 +434,7 @@
 
 TEST_F(ResolverTest, ArraySize_UnsignedLiteral) {
     // var<private> a : array<f32, 10u>;
-    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_u)), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_u)), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -446,7 +447,7 @@
 
 TEST_F(ResolverTest, ArraySize_SignedLiteral) {
     // var<private> a : array<f32, 10i>;
-    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_i)), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_i)), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -461,7 +462,7 @@
     // const size = 10u;
     // var<private> a : array<f32, size>;
     GlobalConst("size", Expr(10_u));
-    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -476,7 +477,7 @@
     // const size = 0;
     // var<private> a : array<f32, size>;
     GlobalConst("size", Expr(10_i));
-    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -491,7 +492,7 @@
     // override size = 10i;
     // var<workgroup> a : array<f32, size>;
     auto* override = Override("size", Expr(10_i));
-    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), type::AddressSpace::kWorkgroup);
+    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -509,8 +510,8 @@
     // var<workgroup> a : array<f32, size>;
     // var<workgroup> b : array<f32, size>;
     auto* override = Override("size", Expr(10_i));
-    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), type::AddressSpace::kWorkgroup);
-    auto* b = GlobalVar("b", ty.array(ty.f32(), Expr("size")), type::AddressSpace::kWorkgroup);
+    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), builtin::AddressSpace::kWorkgroup);
+    auto* b = GlobalVar("b", ty.array(ty.f32(), Expr("size")), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -536,7 +537,7 @@
     // var<workgroup> a : array<f32, size*2>;
     auto* override = Override("size", Expr(10_i));
     auto* cnt = Mul("size", 2_a);
-    auto* a = GlobalVar("a", ty.array(ty.f32(), cnt), type::AddressSpace::kWorkgroup);
+    auto* a = GlobalVar("a", ty.array(ty.f32(), cnt), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -556,8 +557,8 @@
     auto* override = Override("size", Expr(10_i));
     auto* a_cnt = Mul("size", 2_a);
     auto* b_cnt = Mul("size", 2_a);
-    auto* a = GlobalVar("a", ty.array(ty.f32(), a_cnt), type::AddressSpace::kWorkgroup);
-    auto* b = GlobalVar("b", ty.array(ty.f32(), b_cnt), type::AddressSpace::kWorkgroup);
+    auto* a = GlobalVar("a", ty.array(ty.f32(), a_cnt), builtin::AddressSpace::kWorkgroup);
+    auto* b = GlobalVar("b", ty.array(ty.f32(), b_cnt), builtin::AddressSpace::kWorkgroup);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -579,7 +580,7 @@
 }
 
 TEST_F(ResolverTest, Expr_Bitcast) {
-    GlobalVar("name", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("name", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* bitcast = Bitcast<f32>(Expr("name"));
     WrapInFunction(bitcast);
@@ -642,7 +643,7 @@
 }
 
 TEST_F(ResolverTest, Expr_Cast) {
-    GlobalVar("name", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("name", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* cast = Call<f32>("name");
     WrapInFunction(cast);
@@ -700,7 +701,7 @@
 }
 
 TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
-    auto* my_var = GlobalVar("my_var", ty.f32(), type::AddressSpace::kPrivate);
+    auto* my_var = GlobalVar("my_var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* ident = Expr("my_var");
     WrapInFunction(ident);
@@ -801,7 +802,7 @@
     auto* v = Expr("v");
     auto* p = Expr("p");
     auto* v_decl = Decl(Var("v", ty.f32()));
-    auto* p_decl = Decl(Let("p", ty.pointer<f32>(type::AddressSpace::kFunction), AddressOf(v)));
+    auto* p_decl = Decl(Let("p", ty.pointer<f32>(builtin::AddressSpace::kFunction), AddressOf(v)));
     auto* assign = Assign(Deref(p), 1.23_f);
     Func("my_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -877,7 +878,7 @@
         Param("b", ty.u32(), utils::Vector{Builtin(builtin::BuiltinValue::kVertexIndex)});
     auto* param_c = Param("c", ty.u32(), utils::Vector{Location(1_a)});
 
-    GlobalVar("my_vec", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
     auto* func = Func("my_func",
                       utils::Vector{
                           param_a,
@@ -907,7 +908,7 @@
 
 TEST_F(ResolverTest, Function_GlobalVariable_Location) {
     auto* var = GlobalVar(
-        "my_vec", ty.vec4<f32>(), type::AddressSpace::kIn,
+        "my_vec", ty.vec4<f32>(), builtin::AddressSpace::kIn,
         utils::Vector{Location(3_a), Disable(ast::DisabledValidation::kIgnoreAddressSpace)});
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -920,10 +921,10 @@
 TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
     auto* s = Structure("S", utils::Vector{Member("m", ty.u32())});
 
-    auto* sb_var = GlobalVar("sb_var", ty.Of(s), type::AddressSpace::kStorage,
-                             type::Access::kReadWrite, Binding(0_a), Group(0_a));
-    auto* wg_var = GlobalVar("wg_var", ty.f32(), type::AddressSpace::kWorkgroup);
-    auto* priv_var = GlobalVar("priv_var", ty.f32(), type::AddressSpace::kPrivate);
+    auto* sb_var = GlobalVar("sb_var", ty.Of(s), builtin::AddressSpace::kStorage,
+                             builtin::Access::kReadWrite, Binding(0_a), Group(0_a));
+    auto* wg_var = GlobalVar("wg_var", ty.f32(), builtin::AddressSpace::kWorkgroup);
+    auto* priv_var = GlobalVar("priv_var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* func = Func("my_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -966,7 +967,7 @@
 }
 
 TEST_F(ResolverTest, Function_ReturnType_NoLocation) {
-    GlobalVar("my_vec", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
     auto* func = Func("my_func", utils::Empty, ty.vec4<f32>(),
                       utils::Vector{
                           Return("my_vec"),
@@ -988,10 +989,10 @@
 TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
     auto* s = Structure("S", utils::Vector{Member("m", ty.u32())});
 
-    auto* sb_var = GlobalVar("sb_var", ty.Of(s), type::AddressSpace::kStorage,
-                             type::Access::kReadWrite, Binding(0_a), Group(0_a));
-    auto* wg_var = GlobalVar("wg_var", ty.f32(), type::AddressSpace::kWorkgroup);
-    auto* priv_var = GlobalVar("priv_var", ty.f32(), type::AddressSpace::kPrivate);
+    auto* sb_var = GlobalVar("sb_var", ty.Of(s), builtin::AddressSpace::kStorage,
+                             builtin::Access::kReadWrite, Binding(0_a), Group(0_a));
+    auto* wg_var = GlobalVar("wg_var", ty.f32(), builtin::AddressSpace::kWorkgroup);
+    auto* priv_var = GlobalVar("priv_var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     Func("my_func", utils::Empty, ty.f32(),
          utils::Vector{Assign("wg_var", "wg_var"), Assign("sb_var", "sb_var"),
@@ -1240,7 +1241,7 @@
 TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
     auto* st = Structure(
         "S", utils::Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
-    GlobalVar("my_struct", ty.Of(st), type::AddressSpace::kPrivate);
+    GlobalVar("my_struct", ty.Of(st), builtin::AddressSpace::kPrivate);
 
     auto* mem = MemberAccessor("my_struct", "second_member");
     WrapInFunction(mem);
@@ -1261,7 +1262,7 @@
     auto* st = Structure(
         "S", utils::Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
     auto* alias = Alias("alias", ty.Of(st));
-    GlobalVar("my_struct", ty.Of(alias), type::AddressSpace::kPrivate);
+    GlobalVar("my_struct", ty.Of(alias), builtin::AddressSpace::kPrivate);
 
     auto* mem = MemberAccessor("my_struct", "second_member");
     WrapInFunction(mem);
@@ -1278,7 +1279,7 @@
 }
 
 TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
-    GlobalVar("my_vec", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* mem = MemberAccessor("my_vec", "xzyw");
     WrapInFunction(mem);
@@ -1296,7 +1297,7 @@
 }
 
 TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle_SingleElement) {
-    GlobalVar("my_vec", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* mem = MemberAccessor("my_vec", "b");
     WrapInFunction(mem);
@@ -1329,7 +1330,7 @@
 
     auto* stB = Structure("B", utils::Vector{Member("foo", ty.vec4<f32>())});
     auto* stA = Structure("A", utils::Vector{Member("mem", ty.array(ty.Of(stB), 3_i))});
-    GlobalVar("c", ty.Of(stA), type::AddressSpace::kPrivate);
+    GlobalVar("c", ty.Of(stA), builtin::AddressSpace::kPrivate);
 
     auto* mem =
         MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("c", "mem"), 0_i), "foo"), "yx");
@@ -1347,7 +1348,7 @@
 TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
     auto* st = Structure(
         "S", utils::Vector{Member("first_member", ty.f32()), Member("second_member", ty.f32())});
-    GlobalVar("my_struct", ty.Of(st), type::AddressSpace::kPrivate);
+    GlobalVar("my_struct", ty.Of(st), builtin::AddressSpace::kPrivate);
 
     auto* expr = Add(MemberAccessor("my_struct", "first_member"),
                      MemberAccessor("my_struct", "second_member"));
@@ -1650,8 +1651,8 @@
     ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
     SCOPED_TRACE(ss.str());
 
-    GlobalVar("lhs", lhs_type, type::AddressSpace::kPrivate);
-    GlobalVar("rhs", rhs_type, type::AddressSpace::kPrivate);
+    GlobalVar("lhs", lhs_type, builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", rhs_type, builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -1685,8 +1686,8 @@
        << FriendlyName(rhs_type);
     SCOPED_TRACE(ss.str());
 
-    GlobalVar("lhs", lhs_type, type::AddressSpace::kPrivate);
-    GlobalVar("rhs", rhs_type, type::AddressSpace::kPrivate);
+    GlobalVar("lhs", lhs_type, builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", rhs_type, builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -1731,8 +1732,8 @@
     ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
     SCOPED_TRACE(ss.str());
 
-    GlobalVar("lhs", lhs_type, type::AddressSpace::kPrivate);
-    GlobalVar("rhs", rhs_type, type::AddressSpace::kPrivate);
+    GlobalVar("lhs", lhs_type, builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", rhs_type, builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(Source{{12, 34}}, op, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -1771,8 +1772,8 @@
         is_valid_expr = vec_size == mat_cols;
     }
 
-    GlobalVar("lhs", lhs_type, type::AddressSpace::kPrivate);
-    GlobalVar("rhs", rhs_type, type::AddressSpace::kPrivate);
+    GlobalVar("lhs", lhs_type, builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", rhs_type, builtin::AddressSpace::kPrivate);
 
     auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -1808,8 +1809,8 @@
     auto* col = create<type::Vector>(f32, lhs_mat_rows);
     auto* result_type = create<type::Matrix>(col, rhs_mat_cols);
 
-    GlobalVar("lhs", lhs_type, type::AddressSpace::kPrivate);
-    GlobalVar("rhs", rhs_type, type::AddressSpace::kPrivate);
+    GlobalVar("lhs", lhs_type, builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", rhs_type, builtin::AddressSpace::kPrivate);
 
     auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -1837,11 +1838,11 @@
     auto op = GetParam();
 
     if (op == ast::UnaryOp::kNot) {
-        GlobalVar("ident", ty.vec4<bool>(), type::AddressSpace::kPrivate);
+        GlobalVar("ident", ty.vec4<bool>(), builtin::AddressSpace::kPrivate);
     } else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
-        GlobalVar("ident", ty.vec4<i32>(), type::AddressSpace::kPrivate);
+        GlobalVar("ident", ty.vec4<i32>(), builtin::AddressSpace::kPrivate);
     } else {
-        GlobalVar("ident", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+        GlobalVar("ident", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
     }
     auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
     WrapInFunction(der);
@@ -1873,7 +1874,7 @@
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-    EXPECT_EQ(Sem().Get(var)->AddressSpace(), type::AddressSpace::kFunction);
+    EXPECT_EQ(Sem().Get(var)->AddressSpace(), builtin::AddressSpace::kFunction);
 }
 
 TEST_F(ResolverTest, AddressSpace_SetForSampler) {
@@ -1882,7 +1883,7 @@
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-    EXPECT_EQ(Sem().Get(var)->AddressSpace(), type::AddressSpace::kHandle);
+    EXPECT_EQ(Sem().Get(var)->AddressSpace(), builtin::AddressSpace::kHandle);
 }
 
 TEST_F(ResolverTest, AddressSpace_SetForTexture) {
@@ -1891,7 +1892,7 @@
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-    EXPECT_EQ(Sem().Get(var)->AddressSpace(), type::AddressSpace::kHandle);
+    EXPECT_EQ(Sem().Get(var)->AddressSpace(), builtin::AddressSpace::kHandle);
 }
 
 TEST_F(ResolverTest, AddressSpace_DoesNotSetOnConst) {
@@ -1901,19 +1902,19 @@
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-    EXPECT_EQ(Sem().Get(var)->AddressSpace(), type::AddressSpace::kNone);
+    EXPECT_EQ(Sem().Get(var)->AddressSpace(), builtin::AddressSpace::kUndefined);
 }
 
 TEST_F(ResolverTest, Access_SetForStorageBuffer) {
     // struct S { x : i32 };
     // var<storage> g : S;
     auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
-    auto* var = GlobalVar(Source{{56, 78}}, "g", ty.Of(s), type::AddressSpace::kStorage,
+    auto* var = GlobalVar(Source{{56, 78}}, "g", ty.Of(s), builtin::AddressSpace::kStorage,
                           Binding(0_a), Group(0_a));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-    EXPECT_EQ(Sem().Get(var)->Access(), type::Access::kRead);
+    EXPECT_EQ(Sem().Get(var)->Access(), builtin::Access::kRead);
 }
 
 TEST_F(ResolverTest, BindingPoint_SetForResources) {
@@ -1941,11 +1942,11 @@
     // ep_1 -> {}
     // ep_2 -> {}
 
-    GlobalVar("first", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("second", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("call_a", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("call_b", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("call_c", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("first", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("second", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("call_a", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("call_b", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("call_c", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* func_b = Func("b", utils::Empty, ty.f32(),
                         utils::Vector{
@@ -2085,8 +2086,8 @@
         {
             ProgramBuilder b;
             auto* expr = b.Expr(1_i);
-            b.GlobalVar("a", b.ty.i32(), type::AddressSpace::kPrivate, expr);
-            b.GlobalVar("b", b.ty.i32(), type::AddressSpace::kPrivate, expr);
+            b.GlobalVar("a", b.ty.i32(), builtin::AddressSpace::kPrivate, expr);
+            b.GlobalVar("b", b.ty.i32(), builtin::AddressSpace::kPrivate, expr);
             Resolver(&b).Resolve();
         },
         "internal compiler error: AST node 'tint::ast::IntLiteralExpression' was encountered twice "
@@ -2094,7 +2095,7 @@
 }
 
 TEST_F(ResolverTest, UnaryOp_Not) {
-    GlobalVar("ident", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("ident", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
     auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(Source{{12, 34}}, "ident"));
     WrapInFunction(der);
 
@@ -2103,7 +2104,7 @@
 }
 
 TEST_F(ResolverTest, UnaryOp_Complement) {
-    GlobalVar("ident", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("ident", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
     auto* der =
         create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr(Source{{12, 34}}, "ident"));
     WrapInFunction(der);
@@ -2113,7 +2114,7 @@
 }
 
 TEST_F(ResolverTest, UnaryOp_Negation) {
-    GlobalVar("ident", ty.u32(), type::AddressSpace::kPrivate);
+    GlobalVar("ident", ty.u32(), builtin::AddressSpace::kPrivate);
     auto* der =
         create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(Source{{12, 34}}, "ident"));
     WrapInFunction(der);
@@ -2127,9 +2128,10 @@
               Binding(1_a));
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(1_a), Binding(2_a));
 
-    auto* call = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
-    const ast::Function* f = Func("test_function", utils::Empty, ty.void_(), utils::Vector{call},
-                                  utils::Vector{Stage(ast::PipelineStage::kFragment)});
+    auto* call = Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f));
+    const ast::Function* f =
+        Func("test_function", utils::Empty, ty.void_(), utils::Vector{Assign(Phony(), call)},
+             utils::Vector{Stage(ast::PipelineStage::kFragment)});
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
@@ -2145,7 +2147,7 @@
               Binding(1_a));
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(1_a), Binding(2_a));
 
-    auto* inner_call = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
+    auto* inner_call = Assign(Phony(), Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
     const ast::Function* inner_func =
         Func("inner_func", utils::Empty, ty.void_(), utils::Vector{inner_call});
     auto* outer_call = CallStmt(Call("inner_func"));
@@ -2171,10 +2173,10 @@
               Binding(1_a));
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(1_a), Binding(2_a));
 
-    auto* inner_call_1 = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
+    auto* inner_call_1 = Assign(Phony(), Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
     const ast::Function* inner_func_1 =
         Func("inner_func_1", utils::Empty, ty.void_(), utils::Vector{inner_call_1});
-    auto* inner_call_2 = CallStmt(Call("textureSample", "t", "s", vec2<f32>(3_f, 4_f)));
+    auto* inner_call_2 = Assign(Phony(), Call("textureSample", "t", "s", vec2<f32>(3_f, 4_f)));
     const ast::Function* inner_func_2 =
         Func("inner_func_2", utils::Empty, ty.void_(), utils::Vector{inner_call_2});
     auto* outer_call_1 = CallStmt(Call("inner_func_1"));
@@ -2208,10 +2210,10 @@
               Binding(2_a));
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(1_a), Binding(3_a));
 
-    auto* inner_call_1 = CallStmt(Call("textureSample", "t1", "s", vec2<f32>(1_f, 2_f)));
+    auto* inner_call_1 = Assign(Phony(), Call("textureSample", "t1", "s", vec2<f32>(1_f, 2_f)));
     const ast::Function* inner_func_1 =
         Func("inner_func_1", utils::Empty, ty.void_(), utils::Vector{inner_call_1});
-    auto* inner_call_2 = CallStmt(Call("textureSample", "t2", "s", vec2<f32>(3_f, 4_f)));
+    auto* inner_call_2 = Assign(Phony(), Call("textureSample", "t2", "s", vec2<f32>(3_f, 4_f)));
     const ast::Function* inner_func_2 =
         Func("inner_func_2", utils::Empty, ty.void_(), utils::Vector{inner_call_2});
     auto* outer_call_1 = CallStmt(Call("inner_func_1"));
@@ -2272,7 +2274,7 @@
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(0_a), Binding(0_a));
     GlobalVar("t", ty.sampled_texture(type::TextureDimension::k2d, ty.f32()), Group(0_a),
               Binding(1_a));
-    GlobalVar("c", ty.vec2<f32>(), type::AddressSpace::kUniform, Group(0_a), Binding(2_a));
+    GlobalVar("c", ty.vec2<f32>(), builtin::AddressSpace::kUniform, Group(0_a), Binding(2_a));
 
     Func("main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
@@ -2288,9 +2290,9 @@
     Func("helper",
          utils::Vector{
              Param("sl", ty.pointer(ty.sampler(type::SamplerKind::kSampler),
-                                    type::AddressSpace::kFunction)),
+                                    builtin::AddressSpace::kFunction)),
              Param("tl", ty.pointer(ty.sampled_texture(type::TextureDimension::k2d, ty.f32()),
-                                    type::AddressSpace::kFunction)),
+                                    builtin::AddressSpace::kFunction)),
          },
          ty.vec4<f32>(),
          utils::Vector{
@@ -2303,15 +2305,15 @@
 
 TEST_F(ResolverTest, ModuleDependencyOrderedDeclarations) {
     auto* f0 = Func("f0", utils::Empty, ty.void_(), utils::Empty);
-    auto* v0 = GlobalVar("v0", ty.i32(), type::AddressSpace::kPrivate);
+    auto* v0 = GlobalVar("v0", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* a0 = Alias("a0", ty.i32());
     auto* s0 = Structure("s0", utils::Vector{Member("m", ty.i32())});
     auto* f1 = Func("f1", utils::Empty, ty.void_(), utils::Empty);
-    auto* v1 = GlobalVar("v1", ty.i32(), type::AddressSpace::kPrivate);
+    auto* v1 = GlobalVar("v1", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* a1 = Alias("a1", ty.i32());
     auto* s1 = Structure("s1", utils::Vector{Member("m", ty.i32())});
     auto* f2 = Func("f2", utils::Empty, ty.void_(), utils::Empty);
-    auto* v2 = GlobalVar("v2", ty.i32(), type::AddressSpace::kPrivate);
+    auto* v2 = GlobalVar("v2", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* a2 = Alias("a2", ty.i32());
     auto* s2 = Structure("s2", utils::Vector{Member("m", ty.i32())});
 
@@ -2392,5 +2394,45 @@
 
 #endif  // !defined(NDEBUG)
 
+const size_t kMaxNumStructMembers = 16383;
+
+TEST_F(ResolverTest, MaxNumStructMembers_Valid) {
+    utils::Vector<const ast::StructMember*, 0> members;
+    members.Reserve(kMaxNumStructMembers);
+    for (size_t i = 0; i < kMaxNumStructMembers; ++i) {
+        members.Push(Member("m" + std::to_string(i), ty.i32()));
+    }
+    Structure("S", std::move(members));
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNumStructMembers_Invalid) {
+    utils::Vector<const ast::StructMember*, 0> members;
+    members.Reserve(kMaxNumStructMembers + 1);
+    for (size_t i = 0; i < kMaxNumStructMembers + 1; ++i) {
+        members.Push(Member("m" + std::to_string(i), ty.i32()));
+    }
+    Structure(Source{{12, 34}}, "S", std::move(members));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: struct 'S' has 16384 members, maximum is 16383");
+}
+
+TEST_F(ResolverTest, MaxNumStructMembers_WithIgnoreStructMemberLimit_Valid) {
+    utils::Vector<const ast::StructMember*, 0> members;
+    members.Reserve(kMaxNumStructMembers);
+    for (size_t i = 0; i < kMaxNumStructMembers; ++i) {
+        members.Push(Member("m" + std::to_string(i), ty.i32()));
+    }
+
+    // Add 10 more members, but we set the limit to be ignored on the struct
+    for (size_t i = 0; i < 10; ++i) {
+        members.Push(Member("ignored" + std::to_string(i), ty.i32()));
+    }
+
+    Structure("S", std::move(members),
+              utils::Vector{Disable(ast::DisabledValidation::kIgnoreStructMemberLimit)});
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
 }  // namespace
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/resolver_test_helper.h b/src/tint/resolver/resolver_test_helper.h
index 67d71b8..0e1b7d5 100644
--- a/src/tint/resolver/resolver_test_helper.h
+++ b/src/tint/resolver/resolver_test_helper.h
@@ -628,14 +628,14 @@
     /// @param b the ProgramBuilder
     /// @return a new AST alias type
     static inline ast::Type AST(ProgramBuilder& b) {
-        return b.ty.pointer(DataType<T>::AST(b), type::AddressSpace::kPrivate,
-                            type::Access::kUndefined);
+        return b.ty.pointer(DataType<T>::AST(b), builtin::AddressSpace::kPrivate,
+                            builtin::Access::kUndefined);
     }
     /// @param b the ProgramBuilder
     /// @return the semantic aliased type
     static inline const type::Type* Sem(ProgramBuilder& b) {
-        return b.create<type::Pointer>(DataType<T>::Sem(b), type::AddressSpace::kPrivate,
-                                       type::Access::kReadWrite);
+        return b.create<type::Pointer>(DataType<T>::Sem(b), builtin::AddressSpace::kPrivate,
+                                       builtin::Access::kReadWrite);
     }
 
     /// @param b the ProgramBuilder
@@ -643,7 +643,7 @@
     static inline const ast::Expression* Expr(ProgramBuilder& b,
                                               utils::VectorRef<Scalar> /*unused*/) {
         auto sym = b.Symbols().New("global_for_ptr");
-        b.GlobalVar(sym, DataType<T>::AST(b), type::AddressSpace::kPrivate);
+        b.GlobalVar(sym, DataType<T>::AST(b), builtin::AddressSpace::kPrivate);
         return b.AddressOf(sym);
     }
 
diff --git a/src/tint/resolver/root_identifier_test.cc b/src/tint/resolver/root_identifier_test.cc
index 6e81e42..0353ff5 100644
--- a/src/tint/resolver/root_identifier_test.cc
+++ b/src/tint/resolver/root_identifier_test.cc
@@ -27,7 +27,7 @@
 class ResolverRootIdentifierTest : public ResolverTest {};
 
 TEST_F(ResolverRootIdentifierTest, GlobalPrivateVar) {
-    auto* a = GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* expr = Expr(a);
     WrapInFunction(expr);
 
@@ -38,7 +38,7 @@
 }
 
 TEST_F(ResolverRootIdentifierTest, GlobalWorkgroupVar) {
-    auto* a = GlobalVar("a", ty.f32(), type::AddressSpace::kWorkgroup);
+    auto* a = GlobalVar("a", ty.f32(), builtin::AddressSpace::kWorkgroup);
     auto* expr = Expr(a);
     WrapInFunction(expr);
 
@@ -49,7 +49,7 @@
 }
 
 TEST_F(ResolverRootIdentifierTest, GlobalStorageVar) {
-    auto* a = GlobalVar("a", ty.f32(), type::AddressSpace::kStorage, Group(0_a), Binding(0_a));
+    auto* a = GlobalVar("a", ty.f32(), builtin::AddressSpace::kStorage, Group(0_a), Binding(0_a));
     auto* expr = Expr(a);
     WrapInFunction(expr);
 
@@ -60,7 +60,7 @@
 }
 
 TEST_F(ResolverRootIdentifierTest, GlobalUniformVar) {
-    auto* a = GlobalVar("a", ty.f32(), type::AddressSpace::kUniform, Group(0_a), Binding(0_a));
+    auto* a = GlobalVar("a", ty.f32(), builtin::AddressSpace::kUniform, Group(0_a), Binding(0_a));
     auto* expr = Expr(a);
     WrapInFunction(expr);
 
@@ -72,7 +72,7 @@
 
 TEST_F(ResolverRootIdentifierTest, GlobalTextureVar) {
     auto* a = GlobalVar("a", ty.sampled_texture(type::TextureDimension::k2d, ty.f32()),
-                        type::AddressSpace::kNone, Group(0_a), Binding(0_a));
+                        builtin::AddressSpace::kUndefined, Group(0_a), Binding(0_a));
     auto* expr = Expr(a);
     WrapInFunction(Call("textureDimensions", expr));
 
@@ -142,7 +142,7 @@
     // {
     //   let b = a;
     // }
-    auto* param = Param("a", ty.pointer(ty.f32(), type::AddressSpace::kFunction));
+    auto* param = Param("a", ty.pointer(ty.f32(), builtin::AddressSpace::kFunction));
     auto* expr_param = Expr(param);
     auto* let = Let("b", expr_param);
     auto* expr_let = Expr("b");
@@ -199,7 +199,7 @@
     // {
     //   a[2i]
     // }
-    auto* a = GlobalVar("a", ty.array<f32, 4>(), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.array<f32, 4>(), builtin::AddressSpace::kPrivate);
     auto* expr = IndexAccessor(a, 2_i);
     WrapInFunction(expr);
 
@@ -216,7 +216,7 @@
     //   a.f
     // }
     auto* S = Structure("S", utils::Vector{Member("f", ty.f32())});
-    auto* a = GlobalVar("a", ty.Of(S), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.Of(S), builtin::AddressSpace::kPrivate);
     auto* expr = MemberAccessor(a, "f");
     WrapInFunction(expr);
 
@@ -232,7 +232,7 @@
     //   let a_ptr1 = &*&a;
     //   let a_ptr2 = &*a_ptr1;
     // }
-    auto* a = GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* address_of_1 = AddressOf(a);
     auto* deref_1 = Deref(address_of_1);
     auto* address_of_2 = AddressOf(deref_1);
diff --git a/src/tint/resolver/sem_helper.cc b/src/tint/resolver/sem_helper.cc
index 01a737c..45bdf41 100644
--- a/src/tint/resolver/sem_helper.cc
+++ b/src/tint/resolver/sem_helper.cc
@@ -39,77 +39,91 @@
     return sem ? const_cast<type::Type*>(sem->Type()) : nullptr;
 }
 
-void SemHelper::ErrorUnexpectedExprKind(const sem::Expression* expr,
-                                        std::string_view wanted) const {
-    Switch(
+std::string SemHelper::Describe(const sem::Expression* expr) const {
+    return Switch(
         expr,  //
         [&](const sem::VariableUser* var_expr) {
             auto* variable = var_expr->Variable()->Declaration();
             auto name = builder_->Symbols().NameFor(variable->name->symbol);
-            std::string kind = Switch(
+            auto* kind = Switch(
                 variable,                                            //
                 [&](const ast::Var*) { return "var"; },              //
+                [&](const ast::Let*) { return "let"; },              //
                 [&](const ast::Const*) { return "const"; },          //
                 [&](const ast::Parameter*) { return "parameter"; },  //
                 [&](const ast::Override*) { return "override"; },    //
                 [&](Default) { return "variable"; });
-            AddError("cannot use " + kind + " '" + name + "' as " + std::string(wanted),
-                     var_expr->Declaration()->source);
-            NoteDeclarationSource(variable);
+            return std::string(kind) + " '" + name + "'";
         },
         [&](const sem::ValueExpression* val_expr) {
             auto type = val_expr->Type()->FriendlyName(builder_->Symbols());
-            AddError("cannot use expression of type '" + type + "' as " + std::string(wanted),
-                     val_expr->Declaration()->source);
+            return "value expression of type '" + type + "'";
         },
         [&](const sem::TypeExpression* ty_expr) {
             auto name = ty_expr->Type()->FriendlyName(builder_->Symbols());
-            AddError("cannot use type '" + name + "' as " + std::string(wanted),
-                     ty_expr->Declaration()->source);
+            return "type '" + name + "'";
         },
         [&](const sem::FunctionExpression* fn_expr) {
             auto* fn = fn_expr->Function()->Declaration();
             auto name = builder_->Symbols().NameFor(fn->name->symbol);
-            AddError("cannot use function '" + name + "' as " + std::string(wanted),
-                     fn_expr->Declaration()->source);
-            NoteDeclarationSource(fn);
+            return "function '" + name + "'";
         },
-        [&](const sem::BuiltinEnumExpression<type::Access>* access) {
-            AddError("cannot use access '" + utils::ToString(access->Value()) + "' as " +
-                         std::string(wanted),
-                     access->Declaration()->source);
+        [&](const sem::BuiltinEnumExpression<builtin::Access>* access) {
+            return "access '" + utils::ToString(access->Value()) + "'";
         },
-        [&](const sem::BuiltinEnumExpression<type::AddressSpace>* addr) {
-            AddError("cannot use address space '" + utils::ToString(addr->Value()) + "' as " +
-                         std::string(wanted),
-                     addr->Declaration()->source);
+        [&](const sem::BuiltinEnumExpression<builtin::AddressSpace>* addr) {
+            return "address space '" + utils::ToString(addr->Value()) + "'";
         },
-        [&](const sem::BuiltinEnumExpression<type::TexelFormat>* fmt) {
-            AddError("cannot use texel format '" + utils::ToString(fmt->Value()) + "' as " +
-                         std::string(wanted),
-                     fmt->Declaration()->source);
+        [&](const sem::BuiltinEnumExpression<builtin::BuiltinValue>* builtin) {
+            return "builtin value '" + utils::ToString(builtin->Value()) + "'";
         },
-        [&](Default) {
+        [&](const sem::BuiltinEnumExpression<builtin::InterpolationSampling>* fmt) {
+            return "interpolation sampling '" + utils::ToString(fmt->Value()) + "'";
+        },
+        [&](const sem::BuiltinEnumExpression<builtin::InterpolationType>* fmt) {
+            return "interpolation type '" + utils::ToString(fmt->Value()) + "'";
+        },
+        [&](const sem::BuiltinEnumExpression<builtin::TexelFormat>* fmt) {
+            return "texel format '" + utils::ToString(fmt->Value()) + "'";
+        },
+        [&](Default) -> std::string {
             TINT_ICE(Resolver, builder_->Diagnostics())
                 << "unhandled sem::Expression type: " << (expr ? expr->TypeInfo().name : "<null>");
+            return "<unknown>";
         });
 }
 
+void SemHelper::ErrorUnexpectedExprKind(const sem::Expression* expr,
+                                        std::string_view wanted) const {
+    AddError("cannot use " + Describe(expr) + " as " + std::string(wanted),
+             expr->Declaration()->source);
+    NoteDeclarationSource(expr->Declaration());
+}
+
 void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const {
     ErrorUnexpectedExprKind(expr, "value");
     if (auto* ty_expr = expr->As<sem::TypeExpression>()) {
         if (auto* ident = ty_expr->Declaration()->As<ast::IdentifierExpression>()) {
-            AddNote("are you missing '()' for type initializer?",
+            AddNote("are you missing '()' for value constructor?",
                     Source{{ident->source.range.end}});
         }
-        if (auto* str = ty_expr->Type()->As<type::Struct>()) {
-            AddNote("struct '" + str->FriendlyName(builder_->Symbols()) + "' declared here",
-                    str->Source());
-        }
     }
 }
 
 void SemHelper::NoteDeclarationSource(const ast::Node* node) const {
+    if (!node) {
+        return;
+    }
+
+    Switch(
+        Get(node),  //
+        [&](const sem::VariableUser* var_expr) { node = var_expr->Variable()->Declaration(); },
+        [&](const sem::TypeExpression* ty_expr) {
+            Switch(ty_expr->Type(),  //
+                   [&](const sem::Struct* s) { node = s->Declaration(); });
+        },
+        [&](const sem::FunctionExpression* fn_expr) { node = fn_expr->Function()->Declaration(); });
+
     Switch(
         node,
         [&](const ast::Struct* n) {
diff --git a/src/tint/resolver/sem_helper.h b/src/tint/resolver/sem_helper.h
index dd752d3..514367b 100644
--- a/src/tint/resolver/sem_helper.h
+++ b/src/tint/resolver/sem_helper.h
@@ -17,6 +17,9 @@
 
 #include <string>
 
+#include "src/tint/builtin/builtin_value.h"
+#include "src/tint/builtin/interpolation_sampling.h"
+#include "src/tint/builtin/interpolation_type.h"
 #include "src/tint/diagnostic/diagnostic.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/resolver/dependency_graph.h"
@@ -105,11 +108,11 @@
 
     /// @param expr the semantic node
     /// @returns nullptr if @p expr is nullptr, or @p expr cast to
-    /// sem::BuiltinEnumExpression<type::AddressSpace> if the cast is successful, otherwise an error
-    /// diagnostic is raised.
-    sem::BuiltinEnumExpression<type::AddressSpace>* AsAddressSpace(sem::Expression* expr) const {
+    /// sem::BuiltinEnumExpression<builtin::AddressSpace> if the cast is successful, otherwise an
+    /// error diagnostic is raised.
+    sem::BuiltinEnumExpression<builtin::AddressSpace>* AsAddressSpace(sem::Expression* expr) const {
         if (TINT_LIKELY(expr)) {
-            auto* enum_expr = expr->As<sem::BuiltinEnumExpression<type::AddressSpace>>();
+            auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::AddressSpace>>();
             if (TINT_LIKELY(enum_expr)) {
                 return enum_expr;
             }
@@ -120,11 +123,26 @@
 
     /// @param expr the semantic node
     /// @returns nullptr if @p expr is nullptr, or @p expr cast to
+    /// sem::BuiltinEnumExpression<builtin::BuiltinValue> if the cast is successful, otherwise an
+    /// error diagnostic is raised.
+    sem::BuiltinEnumExpression<builtin::BuiltinValue>* AsBuiltinValue(sem::Expression* expr) const {
+        if (TINT_LIKELY(expr)) {
+            auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::BuiltinValue>>();
+            if (TINT_LIKELY(enum_expr)) {
+                return enum_expr;
+            }
+            ErrorUnexpectedExprKind(expr, "builtin value");
+        }
+        return nullptr;
+    }
+
+    /// @param expr the semantic node
+    /// @returns nullptr if @p expr is nullptr, or @p expr cast to
     /// sem::BuiltinEnumExpression<type::TexelFormat> if the cast is successful, otherwise an error
     /// diagnostic is raised.
-    sem::BuiltinEnumExpression<type::TexelFormat>* AsTexelFormat(sem::Expression* expr) const {
+    sem::BuiltinEnumExpression<builtin::TexelFormat>* AsTexelFormat(sem::Expression* expr) const {
         if (TINT_LIKELY(expr)) {
-            auto* enum_expr = expr->As<sem::BuiltinEnumExpression<type::TexelFormat>>();
+            auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::TexelFormat>>();
             if (TINT_LIKELY(enum_expr)) {
                 return enum_expr;
             }
@@ -135,11 +153,11 @@
 
     /// @param expr the semantic node
     /// @returns nullptr if @p expr is nullptr, or @p expr cast to
-    /// sem::BuiltinEnumExpression<type::Access> if the cast is successful, otherwise an error
+    /// sem::BuiltinEnumExpression<builtin::Access> if the cast is successful, otherwise an error
     /// diagnostic is raised.
-    sem::BuiltinEnumExpression<type::Access>* AsAccess(sem::Expression* expr) const {
+    sem::BuiltinEnumExpression<builtin::Access>* AsAccess(sem::Expression* expr) const {
         if (TINT_LIKELY(expr)) {
-            auto* enum_expr = expr->As<sem::BuiltinEnumExpression<type::Access>>();
+            auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::Access>>();
             if (TINT_LIKELY(enum_expr)) {
                 return enum_expr;
             }
@@ -148,6 +166,39 @@
         return nullptr;
     }
 
+    /// @param expr the semantic node
+    /// @returns nullptr if @p expr is nullptr, or @p expr cast to
+    /// sem::BuiltinEnumExpression<builtin::InterpolationSampling> if the cast is successful,
+    /// otherwise an error diagnostic is raised.
+    sem::BuiltinEnumExpression<builtin::InterpolationSampling>* AsInterpolationSampling(
+        sem::Expression* expr) const {
+        if (TINT_LIKELY(expr)) {
+            auto* enum_expr =
+                expr->As<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>();
+            if (TINT_LIKELY(enum_expr)) {
+                return enum_expr;
+            }
+            ErrorUnexpectedExprKind(expr, "interpolation sampling");
+        }
+        return nullptr;
+    }
+
+    /// @param expr the semantic node
+    /// @returns nullptr if @p expr is nullptr, or @p expr cast to
+    /// sem::BuiltinEnumExpression<builtin::InterpolationType> if the cast is successful, otherwise
+    /// an error diagnostic is raised.
+    sem::BuiltinEnumExpression<builtin::InterpolationType>* AsInterpolationType(
+        sem::Expression* expr) const {
+        if (TINT_LIKELY(expr)) {
+            auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::InterpolationType>>();
+            if (TINT_LIKELY(enum_expr)) {
+                return enum_expr;
+            }
+            ErrorUnexpectedExprKind(expr, "interpolation type");
+        }
+        return nullptr;
+    }
+
     /// @returns the resolved type of the ast::Expression @p expr
     /// @param expr the expression
     type::Type* TypeOf(const ast::Expression* expr) const;
@@ -175,6 +226,10 @@
     /// @param node the AST node.
     void NoteDeclarationSource(const ast::Node* node) const;
 
+    /// @param expr the expression to describe
+    /// @return a string that describes @p expr. Useful for diagnostics.
+    std::string Describe(const sem::Expression* expr) const;
+
   private:
     /// Adds the given error message to the diagnostics
     void AddError(const std::string& msg, const Source& source) const;
diff --git a/src/tint/resolver/side_effects_test.cc b/src/tint/resolver/side_effects_test.cc
index 456b371..f6ce399 100644
--- a/src/tint/resolver/side_effects_test.cc
+++ b/src/tint/resolver/side_effects_test.cc
@@ -15,7 +15,9 @@
 #include "src/tint/resolver/resolver.h"
 
 #include "gtest/gtest.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/builtin/extension.h"
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/index_accessor_expression.h"
 #include "src/tint/sem/member_accessor_expression.h"
@@ -32,7 +34,7 @@
     template <typename T>
     void MakeSideEffectFunc(const char* name) {
         auto global = Sym();
-        GlobalVar(global, ty.Of<T>(), type::AddressSpace::kPrivate);
+        GlobalVar(global, ty.Of<T>(), builtin::AddressSpace::kPrivate);
         auto local = Sym();
         Func(name, utils::Empty, ty.Of<T>(),
              utils::Vector{
@@ -45,7 +47,7 @@
     template <typename MAKE_TYPE_FUNC>
     void MakeSideEffectFunc(const char* name, MAKE_TYPE_FUNC make_type) {
         auto global = Sym();
-        GlobalVar(global, make_type(), type::AddressSpace::kPrivate);
+        GlobalVar(global, make_type(), builtin::AddressSpace::kPrivate);
         auto local = Sym();
         Func(name, utils::Empty, make_type(),
              utils::Vector{
@@ -90,7 +92,7 @@
 }
 
 TEST_F(SideEffectsTest, Call_Builtin_NoSE) {
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("dpdx", "a");
     Func("f", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
          utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
@@ -116,7 +118,7 @@
 }
 
 TEST_F(SideEffectsTest, Call_Builtin_SE) {
-    GlobalVar("a", ty.atomic(ty.i32()), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic(ty.i32()), builtin::AddressSpace::kWorkgroup);
     auto* expr = Call("atomicAdd", AddressOf("a"), 1_i);
     WrapInFunction(expr);
 
@@ -127,21 +129,24 @@
     EXPECT_TRUE(sem->HasSideEffects());
 }
 
-namespace builtin {
+namespace builtin_tests {
 struct Case {
     const char* name;
     utils::Vector<const char*, 3> args;
     bool has_side_effects;
+    bool returns_value;
     ast::PipelineStage pipeline_stage;
 };
 static Case C(const char* name,
               utils::VectorRef<const char*> args,
               bool has_side_effects,
+              bool returns_value,
               ast::PipelineStage stage = ast::PipelineStage::kFragment) {
     Case c;
     c.name = name;
     c.args = std::move(args);
     c.has_side_effects = has_side_effects;
+    c.returns_value = returns_value;
     c.pipeline_stage = stage;
     return c;
 }
@@ -153,8 +158,7 @@
             o << ", ";
         }
     }
-    o << "), ";
-    o << "has_side_effects = " << c.has_side_effects;
+    o << ")";
     return o;
 }
 
@@ -165,22 +169,22 @@
     auto& c = GetParam();
 
     uint32_t next_binding = 0;
-    GlobalVar("f", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("i", ty.i32(), type::AddressSpace::kPrivate);
-    GlobalVar("u", ty.u32(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("vf", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("vf2", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("vi2", ty.vec2<i32>(), type::AddressSpace::kPrivate);
-    GlobalVar("vf4", ty.vec4<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("vb", ty.vec3<bool>(), type::AddressSpace::kPrivate);
-    GlobalVar("m", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("arr", ty.array<f32, 10>(), type::AddressSpace::kPrivate);
-    GlobalVar("storage_arr", ty.array<f32>(), type::AddressSpace::kStorage, Group(0_a),
+    GlobalVar("f", ty.f32(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("i", ty.i32(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("u", ty.u32(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("vf", ty.vec3<f32>(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("vf2", ty.vec2<f32>(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("vi2", ty.vec2<i32>(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("vf4", ty.vec4<f32>(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("vb", ty.vec3<bool>(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("m", ty.mat3x3<f32>(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("arr", ty.array<f32, 10>(), tint::builtin::AddressSpace::kPrivate);
+    GlobalVar("storage_arr", ty.array<f32>(), tint::builtin::AddressSpace::kStorage, Group(0_a),
               Binding(AInt(next_binding++)));
-    GlobalVar("workgroup_arr", ty.array<f32, 4>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("a", ty.atomic(ty.i32()), type::AddressSpace::kStorage, type::Access::kReadWrite,
-              Group(0_a), Binding(AInt(next_binding++)));
+    GlobalVar("workgroup_arr", ty.array<f32, 4>(), tint::builtin::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic(ty.i32()), tint::builtin::AddressSpace::kStorage,
+              tint::builtin::Access::kReadWrite, Group(0_a), Binding(AInt(next_binding++)));
     if (c.pipeline_stage != ast::PipelineStage::kCompute) {
         GlobalVar("t2d", ty.sampled_texture(type::TextureDimension::k2d, ty.f32()), Group(0_a),
                   Binding(AInt(next_binding++)));
@@ -190,10 +194,11 @@
                   Group(0_a), Binding(AInt(next_binding++)));
         GlobalVar("t2d_multi", ty.multisampled_texture(type::TextureDimension::k2d, ty.f32()),
                   Group(0_a), Binding(AInt(next_binding++)));
-        GlobalVar("tstorage2d",
-                  ty.storage_texture(type::TextureDimension::k2d, type::TexelFormat::kR32Float,
-                                     type::Access::kWrite),
-                  Group(0_a), Binding(AInt(next_binding++)));
+        GlobalVar(
+            "tstorage2d",
+            ty.storage_texture(type::TextureDimension::k2d, tint::builtin::TexelFormat::kR32Float,
+                               tint::builtin::Access::kWrite),
+            Group(0_a), Binding(AInt(next_binding++)));
         GlobalVar("s2d", ty.sampler(type::SamplerKind::kSampler), Group(0_a),
                   Binding(AInt(next_binding++)));
         GlobalVar("scomp", ty.sampler(type::SamplerKind::kComparisonSampler), Group(0_a),
@@ -219,7 +224,11 @@
         attrs.Push(WorkgroupSize(Expr(1_u)));
     }
 
-    stmts.Push(CallStmt(expr));
+    if (c.returns_value) {
+        stmts.Push(Assign(Phony(), expr));
+    } else {
+        stmts.Push(CallStmt(expr));
+    }
 
     Func("func", utils::Empty, ty.void_(), stmts, attrs);
 
@@ -234,120 +243,124 @@
     SideEffectsBuiltinTest,
     testing::ValuesIn(std::vector<Case>{
         // No side-effect builts
-        C("abs", utils::Vector{"f"}, false),                                                    //
-        C("acos", utils::Vector{"f"}, false),                                                   //
-        C("acosh", utils::Vector{"f"}, false),                                                  //
-        C("all", utils::Vector{"vb"}, false),                                                   //
-        C("any", utils::Vector{"vb"}, false),                                                   //
-        C("arrayLength", utils::Vector{"pstorage_arr"}, false),                                 //
-        C("asin", utils::Vector{"f"}, false),                                                   //
-        C("asinh", utils::Vector{"f"}, false),                                                  //
-        C("atan", utils::Vector{"f"}, false),                                                   //
-        C("atan2", utils::Vector{"f", "f"}, false),                                             //
-        C("atanh", utils::Vector{"f"}, false),                                                  //
-        C("atomicLoad", utils::Vector{"pa"}, false),                                            //
-        C("ceil", utils::Vector{"f"}, false),                                                   //
-        C("clamp", utils::Vector{"f", "f", "f"}, false),                                        //
-        C("cos", utils::Vector{"f"}, false),                                                    //
-        C("cosh", utils::Vector{"f"}, false),                                                   //
-        C("countLeadingZeros", utils::Vector{"i"}, false),                                      //
-        C("countOneBits", utils::Vector{"i"}, false),                                           //
-        C("countTrailingZeros", utils::Vector{"i"}, false),                                     //
-        C("cross", utils::Vector{"vf", "vf"}, false),                                           //
-        C("degrees", utils::Vector{"f"}, false),                                                //
-        C("determinant", utils::Vector{"m"}, false),                                            //
-        C("distance", utils::Vector{"f", "f"}, false),                                          //
-        C("dot", utils::Vector{"vf", "vf"}, false),                                             //
-        C("dot4I8Packed", utils::Vector{"u", "u"}, false),                                      //
-        C("dot4U8Packed", utils::Vector{"u", "u"}, false),                                      //
-        C("exp", utils::Vector{"f"}, false),                                                    //
-        C("exp2", utils::Vector{"f"}, false),                                                   //
-        C("extractBits", utils::Vector{"i", "u", "u"}, false),                                  //
-        C("faceForward", utils::Vector{"vf", "vf", "vf"}, false),                               //
-        C("firstLeadingBit", utils::Vector{"u"}, false),                                        //
-        C("firstTrailingBit", utils::Vector{"u"}, false),                                       //
-        C("floor", utils::Vector{"f"}, false),                                                  //
-        C("fma", utils::Vector{"f", "f", "f"}, false),                                          //
-        C("fract", utils::Vector{"vf"}, false),                                                 //
-        C("frexp", utils::Vector{"f"}, false),                                                  //
-        C("insertBits", utils::Vector{"i", "i", "u", "u"}, false),                              //
-        C("inverseSqrt", utils::Vector{"f"}, false),                                            //
-        C("ldexp", utils::Vector{"f", "i"}, false),                                             //
-        C("length", utils::Vector{"vf"}, false),                                                //
-        C("log", utils::Vector{"f"}, false),                                                    //
-        C("log2", utils::Vector{"f"}, false),                                                   //
-        C("max", utils::Vector{"f", "f"}, false),                                               //
-        C("min", utils::Vector{"f", "f"}, false),                                               //
-        C("mix", utils::Vector{"f", "f", "f"}, false),                                          //
-        C("modf", utils::Vector{"f"}, false),                                                   //
-        C("normalize", utils::Vector{"vf"}, false),                                             //
-        C("pack2x16float", utils::Vector{"vf2"}, false),                                        //
-        C("pack2x16snorm", utils::Vector{"vf2"}, false),                                        //
-        C("pack2x16unorm", utils::Vector{"vf2"}, false),                                        //
-        C("pack4x8snorm", utils::Vector{"vf4"}, false),                                         //
-        C("pack4x8unorm", utils::Vector{"vf4"}, false),                                         //
-        C("pow", utils::Vector{"f", "f"}, false),                                               //
-        C("radians", utils::Vector{"f"}, false),                                                //
-        C("reflect", utils::Vector{"vf", "vf"}, false),                                         //
-        C("refract", utils::Vector{"vf", "vf", "f"}, false),                                    //
-        C("reverseBits", utils::Vector{"u"}, false),                                            //
-        C("round", utils::Vector{"f"}, false),                                                  //
-        C("select", utils::Vector{"f", "f", "b"}, false),                                       //
-        C("sign", utils::Vector{"f"}, false),                                                   //
-        C("sin", utils::Vector{"f"}, false),                                                    //
-        C("sinh", utils::Vector{"f"}, false),                                                   //
-        C("smoothstep", utils::Vector{"f", "f", "f"}, false),                                   //
-        C("sqrt", utils::Vector{"f"}, false),                                                   //
-        C("step", utils::Vector{"f", "f"}, false),                                              //
-        C("tan", utils::Vector{"f"}, false),                                                    //
-        C("tanh", utils::Vector{"f"}, false),                                                   //
-        C("textureDimensions", utils::Vector{"t2d"}, false),                                    //
-        C("textureGather", utils::Vector{"tdepth2d", "s2d", "vf2"}, false),                     //
-        C("textureGatherCompare", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false),       //
-        C("textureLoad", utils::Vector{"t2d", "vi2", "i"}, false),                              //
-        C("textureNumLayers", utils::Vector{"t2d_arr"}, false),                                 //
-        C("textureNumLevels", utils::Vector{"t2d"}, false),                                     //
-        C("textureNumSamples", utils::Vector{"t2d_multi"}, false),                              //
-        C("textureSampleCompareLevel", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false),  //
-        C("textureSampleGrad", utils::Vector{"t2d", "s2d", "vf2", "vf2", "vf2"}, false),        //
-        C("textureSampleLevel", utils::Vector{"t2d", "s2d", "vf2", "f"}, false),                //
-        C("transpose", utils::Vector{"m"}, false),                                              //
-        C("trunc", utils::Vector{"f"}, false),                                                  //
-        C("unpack2x16float", utils::Vector{"u"}, false),                                        //
-        C("unpack2x16snorm", utils::Vector{"u"}, false),                                        //
-        C("unpack2x16unorm", utils::Vector{"u"}, false),                                        //
-        C("unpack4x8snorm", utils::Vector{"u"}, false),                                         //
-        C("unpack4x8unorm", utils::Vector{"u"}, false),                                         //
-        C("storageBarrier", utils::Empty, false, ast::PipelineStage::kCompute),                 //
-        C("workgroupBarrier", utils::Empty, false, ast::PipelineStage::kCompute),               //
-        C("textureSample", utils::Vector{"t2d", "s2d", "vf2"}, false),                          //
-        C("textureSampleBias", utils::Vector{"t2d", "s2d", "vf2", "f"}, false),                 //
-        C("textureSampleCompare", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false),       //
-        C("dpdx", utils::Vector{"f"}, false),                                                   //
-        C("dpdxCoarse", utils::Vector{"f"}, false),                                             //
-        C("dpdxFine", utils::Vector{"f"}, false),                                               //
-        C("dpdy", utils::Vector{"f"}, false),                                                   //
-        C("dpdyCoarse", utils::Vector{"f"}, false),                                             //
-        C("dpdyFine", utils::Vector{"f"}, false),                                               //
-        C("fwidth", utils::Vector{"f"}, false),                                                 //
-        C("fwidthCoarse", utils::Vector{"f"}, false),                                           //
-        C("fwidthFine", utils::Vector{"f"}, false),                                             //
+        C("abs", utils::Vector{"f"}, false, true),                                               //
+        C("acos", utils::Vector{"f"}, false, true),                                              //
+        C("acosh", utils::Vector{"f"}, false, true),                                             //
+        C("all", utils::Vector{"vb"}, false, true),                                              //
+        C("any", utils::Vector{"vb"}, false, true),                                              //
+        C("arrayLength", utils::Vector{"pstorage_arr"}, false, true),                            //
+        C("asin", utils::Vector{"f"}, false, true),                                              //
+        C("asinh", utils::Vector{"f"}, false, true),                                             //
+        C("atan", utils::Vector{"f"}, false, true),                                              //
+        C("atan2", utils::Vector{"f", "f"}, false, true),                                        //
+        C("atanh", utils::Vector{"f"}, false, true),                                             //
+        C("atomicLoad", utils::Vector{"pa"}, false, true),                                       //
+        C("ceil", utils::Vector{"f"}, false, true),                                              //
+        C("clamp", utils::Vector{"f", "f", "f"}, false, true),                                   //
+        C("cos", utils::Vector{"f"}, false, true),                                               //
+        C("cosh", utils::Vector{"f"}, false, true),                                              //
+        C("countLeadingZeros", utils::Vector{"i"}, false, true),                                 //
+        C("countOneBits", utils::Vector{"i"}, false, true),                                      //
+        C("countTrailingZeros", utils::Vector{"i"}, false, true),                                //
+        C("cross", utils::Vector{"vf", "vf"}, false, true),                                      //
+        C("degrees", utils::Vector{"f"}, false, true),                                           //
+        C("determinant", utils::Vector{"m"}, false, true),                                       //
+        C("distance", utils::Vector{"f", "f"}, false, true),                                     //
+        C("dot", utils::Vector{"vf", "vf"}, false, true),                                        //
+        C("dot4I8Packed", utils::Vector{"u", "u"}, false, true),                                 //
+        C("dot4U8Packed", utils::Vector{"u", "u"}, false, true),                                 //
+        C("exp", utils::Vector{"f"}, false, true),                                               //
+        C("exp2", utils::Vector{"f"}, false, true),                                              //
+        C("extractBits", utils::Vector{"i", "u", "u"}, false, true),                             //
+        C("faceForward", utils::Vector{"vf", "vf", "vf"}, false, true),                          //
+        C("firstLeadingBit", utils::Vector{"u"}, false, true),                                   //
+        C("firstTrailingBit", utils::Vector{"u"}, false, true),                                  //
+        C("floor", utils::Vector{"f"}, false, true),                                             //
+        C("fma", utils::Vector{"f", "f", "f"}, false, true),                                     //
+        C("fract", utils::Vector{"vf"}, false, true),                                            //
+        C("frexp", utils::Vector{"f"}, false, true),                                             //
+        C("insertBits", utils::Vector{"i", "i", "u", "u"}, false, true),                         //
+        C("inverseSqrt", utils::Vector{"f"}, false, true),                                       //
+        C("ldexp", utils::Vector{"f", "i"}, false, true),                                        //
+        C("length", utils::Vector{"vf"}, false, true),                                           //
+        C("log", utils::Vector{"f"}, false, true),                                               //
+        C("log2", utils::Vector{"f"}, false, true),                                              //
+        C("max", utils::Vector{"f", "f"}, false, true),                                          //
+        C("min", utils::Vector{"f", "f"}, false, true),                                          //
+        C("mix", utils::Vector{"f", "f", "f"}, false, true),                                     //
+        C("modf", utils::Vector{"f"}, false, true),                                              //
+        C("normalize", utils::Vector{"vf"}, false, true),                                        //
+        C("pack2x16float", utils::Vector{"vf2"}, false, true),                                   //
+        C("pack2x16snorm", utils::Vector{"vf2"}, false, true),                                   //
+        C("pack2x16unorm", utils::Vector{"vf2"}, false, true),                                   //
+        C("pack4x8snorm", utils::Vector{"vf4"}, false, true),                                    //
+        C("pack4x8unorm", utils::Vector{"vf4"}, false, true),                                    //
+        C("pow", utils::Vector{"f", "f"}, false, true),                                          //
+        C("radians", utils::Vector{"f"}, false, true),                                           //
+        C("reflect", utils::Vector{"vf", "vf"}, false, true),                                    //
+        C("refract", utils::Vector{"vf", "vf", "f"}, false, true),                               //
+        C("reverseBits", utils::Vector{"u"}, false, true),                                       //
+        C("round", utils::Vector{"f"}, false, true),                                             //
+        C("select", utils::Vector{"f", "f", "b"}, false, true),                                  //
+        C("sign", utils::Vector{"f"}, false, true),                                              //
+        C("sin", utils::Vector{"f"}, false, true),                                               //
+        C("sinh", utils::Vector{"f"}, false, true),                                              //
+        C("smoothstep", utils::Vector{"f", "f", "f"}, false, true),                              //
+        C("sqrt", utils::Vector{"f"}, false, true),                                              //
+        C("step", utils::Vector{"f", "f"}, false, true),                                         //
+        C("tan", utils::Vector{"f"}, false, true),                                               //
+        C("tanh", utils::Vector{"f"}, false, true),                                              //
+        C("textureDimensions", utils::Vector{"t2d"}, false, true),                               //
+        C("textureGather", utils::Vector{"tdepth2d", "s2d", "vf2"}, false, true),                //
+        C("textureGatherCompare", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false, true),  //
+        C("textureLoad", utils::Vector{"t2d", "vi2", "i"}, false, true),                         //
+        C("textureNumLayers", utils::Vector{"t2d_arr"}, false, true),                            //
+        C("textureNumLevels", utils::Vector{"t2d"}, false, true),                                //
+        C("textureNumSamples", utils::Vector{"t2d_multi"}, false, true),                         //
+        C("textureSampleCompareLevel",
+          utils::Vector{"tdepth2d", "scomp", "vf2", "f"},
+          false,
+          true),                                                                                 //
+        C("textureSampleGrad", utils::Vector{"t2d", "s2d", "vf2", "vf2", "vf2"}, false, true),   //
+        C("textureSampleLevel", utils::Vector{"t2d", "s2d", "vf2", "f"}, false, true),           //
+        C("transpose", utils::Vector{"m"}, false, true),                                         //
+        C("trunc", utils::Vector{"f"}, false, true),                                             //
+        C("unpack2x16float", utils::Vector{"u"}, false, true),                                   //
+        C("unpack2x16snorm", utils::Vector{"u"}, false, true),                                   //
+        C("unpack2x16unorm", utils::Vector{"u"}, false, true),                                   //
+        C("unpack4x8snorm", utils::Vector{"u"}, false, true),                                    //
+        C("unpack4x8unorm", utils::Vector{"u"}, false, true),                                    //
+        C("storageBarrier", utils::Empty, false, false, ast::PipelineStage::kCompute),           //
+        C("workgroupBarrier", utils::Empty, false, false, ast::PipelineStage::kCompute),         //
+        C("textureSample", utils::Vector{"t2d", "s2d", "vf2"}, false, true),                     //
+        C("textureSampleBias", utils::Vector{"t2d", "s2d", "vf2", "f"}, false, true),            //
+        C("textureSampleCompare", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false, true),  //
+        C("dpdx", utils::Vector{"f"}, false, true),                                              //
+        C("dpdxCoarse", utils::Vector{"f"}, false, true),                                        //
+        C("dpdxFine", utils::Vector{"f"}, false, true),                                          //
+        C("dpdy", utils::Vector{"f"}, false, true),                                              //
+        C("dpdyCoarse", utils::Vector{"f"}, false, true),                                        //
+        C("dpdyFine", utils::Vector{"f"}, false, true),                                          //
+        C("fwidth", utils::Vector{"f"}, false, true),                                            //
+        C("fwidthCoarse", utils::Vector{"f"}, false, true),                                      //
+        C("fwidthFine", utils::Vector{"f"}, false, true),                                        //
 
         // Side-effect builtins
-        C("atomicAdd", utils::Vector{"pa", "i"}, true),                       //
-        C("atomicAnd", utils::Vector{"pa", "i"}, true),                       //
-        C("atomicCompareExchangeWeak", utils::Vector{"pa", "i", "i"}, true),  //
-        C("atomicExchange", utils::Vector{"pa", "i"}, true),                  //
-        C("atomicMax", utils::Vector{"pa", "i"}, true),                       //
-        C("atomicMin", utils::Vector{"pa", "i"}, true),                       //
-        C("atomicOr", utils::Vector{"pa", "i"}, true),                        //
-        C("atomicStore", utils::Vector{"pa", "i"}, true),                     //
-        C("atomicSub", utils::Vector{"pa", "i"}, true),                       //
-        C("atomicXor", utils::Vector{"pa", "i"}, true),                       //
-        C("textureStore", utils::Vector{"tstorage2d", "vi2", "vf4"}, true),   //
+        C("atomicAdd", utils::Vector{"pa", "i"}, true, true),                       //
+        C("atomicAnd", utils::Vector{"pa", "i"}, true, true),                       //
+        C("atomicCompareExchangeWeak", utils::Vector{"pa", "i", "i"}, true, true),  //
+        C("atomicExchange", utils::Vector{"pa", "i"}, true, true),                  //
+        C("atomicMax", utils::Vector{"pa", "i"}, true, true),                       //
+        C("atomicMin", utils::Vector{"pa", "i"}, true, true),                       //
+        C("atomicOr", utils::Vector{"pa", "i"}, true, true),                        //
+        C("atomicStore", utils::Vector{"pa", "i"}, true, false),                    //
+        C("atomicSub", utils::Vector{"pa", "i"}, true, true),                       //
+        C("atomicXor", utils::Vector{"pa", "i"}, true, true),                       //
+        C("textureStore", utils::Vector{"tstorage2d", "vi2", "vf4"}, true, false),  //
         C("workgroupUniformLoad",
           utils::Vector{"pworkgroup_arr"},
           true,
+          true,
           ast::PipelineStage::kCompute),  //
 
         // Unimplemented builtins
@@ -355,7 +368,7 @@
         // C("saturate", utils::Vector{"f"}, false), //
     }));
 
-}  // namespace builtin
+}  // namespace builtin_tests
 
 TEST_F(SideEffectsTest, Call_Function) {
     Func("f", utils::Empty, ty.i32(), utils::Vector{Return(1_i)});
diff --git a/src/tint/resolver/struct_address_space_use_test.cc b/src/tint/resolver/struct_address_space_use_test.cc
index 2d011bb..aeb5c31 100644
--- a/src/tint/resolver/struct_address_space_use_test.cc
+++ b/src/tint/resolver/struct_address_space_use_test.cc
@@ -46,7 +46,7 @@
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kNone));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kUndefined));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableFromReturnType) {
@@ -58,55 +58,55 @@
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kNone));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kUndefined));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableFromGlobal) {
     auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
 
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kPrivate));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kPrivate));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableViaGlobalAlias) {
     auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
     auto* a = Alias("A", ty.Of(s));
-    GlobalVar("g", ty.Of(a), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(a), builtin::AddressSpace::kPrivate);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kPrivate));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kPrivate));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableViaGlobalStruct) {
     auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
     auto* o = Structure("O", utils::Vector{Member("a", ty.Of(s))});
-    GlobalVar("g", ty.Of(o), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(o), builtin::AddressSpace::kPrivate);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kPrivate));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kPrivate));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableViaGlobalArray) {
     auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
     auto a = ty.array(ty.Of(s), 3_u);
-    GlobalVar("g", a, type::AddressSpace::kPrivate);
+    GlobalVar("g", a, builtin::AddressSpace::kPrivate);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kPrivate));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kPrivate));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableFromLocal) {
@@ -118,7 +118,7 @@
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kFunction));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kFunction));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableViaLocalAlias) {
@@ -130,7 +130,7 @@
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kFunction));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kFunction));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableViaLocalStruct) {
@@ -142,7 +142,7 @@
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kFunction));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kFunction));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructReachableViaLocalArray) {
@@ -154,13 +154,13 @@
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(type::AddressSpace::kFunction));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kFunction));
 }
 
 TEST_F(ResolverAddressSpaceUseTest, StructMultipleAddressSpaceUses) {
     auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
-    GlobalVar("x", ty.Of(s), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
-    GlobalVar("y", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("x", ty.Of(s), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+    GlobalVar("y", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(0_a));
     WrapInFunction(Var("g", ty.Of(s)));
 
@@ -168,9 +168,9 @@
 
     auto* sem = TypeOf(s)->As<sem::Struct>();
     ASSERT_NE(sem, nullptr);
-    EXPECT_THAT(sem->AddressSpaceUsage(),
-                UnorderedElementsAre(type::AddressSpace::kUniform, type::AddressSpace::kStorage,
-                                     type::AddressSpace::kFunction));
+    EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kUniform,
+                                                               builtin::AddressSpace::kStorage,
+                                                               builtin::AddressSpace::kFunction));
 }
 
 }  // namespace
diff --git a/src/tint/resolver/struct_pipeline_stage_use_test.cc b/src/tint/resolver/struct_pipeline_stage_use_test.cc
index 90e9505..4707650 100644
--- a/src/tint/resolver/struct_pipeline_stage_use_test.cc
+++ b/src/tint/resolver/struct_pipeline_stage_use_test.cc
@@ -16,6 +16,7 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/ast/stage_attribute.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/struct.h"
 
diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc
index efc55f0..fe9622b 100644
--- a/src/tint/resolver/type_validation_test.cc
+++ b/src/tint/resolver/type_validation_test.cc
@@ -95,7 +95,7 @@
 
 TEST_F(ResolverTypeValidationTest, GlobalVariableWithAddressSpace_Pass) {
     // var<private> global_var: f32;
-    GlobalVar(Source{{12, 34}}, "global_var", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{12, 34}}, "global_var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -111,9 +111,10 @@
     // var global_var0 : f32 = 0.1;
     // var global_var1 : i32 = 0;
 
-    GlobalVar("global_var0", ty.f32(), type::AddressSpace::kPrivate, Expr(0.1_f));
+    GlobalVar("global_var0", ty.f32(), builtin::AddressSpace::kPrivate, Expr(0.1_f));
 
-    GlobalVar(Source{{12, 34}}, "global_var1", ty.f32(), type::AddressSpace::kPrivate, Expr(1_f));
+    GlobalVar(Source{{12, 34}}, "global_var1", ty.f32(), builtin::AddressSpace::kPrivate,
+              Expr(1_f));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -129,7 +130,7 @@
              Decl(Var("a", ty.f32(), Expr(2_f))),
          });
 
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate, Expr(2.1_f));
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate, Expr(2.1_f));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -193,19 +194,22 @@
 
 TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Pass) {
     // var<private> a : array<f32, 4>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_a)), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_a)),
+              builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Pass) {
     // var<private> a : array<f32, 4u>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_u)), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_u)),
+              builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Pass) {
     // var<private> a : array<f32, 4i>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_i)), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_i)),
+              builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
@@ -214,7 +218,7 @@
     // var<private> a : array<f32, size>;
     GlobalConst("size", Expr(4_u));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
@@ -223,34 +227,38 @@
     // var<private> a : array<f32, size>;
     GlobalConst("size", Expr(4_i));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Zero) {
     // var<private> a : array<f32, 0>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_a)), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_a)),
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: array count (0) must be greater than 0");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Zero) {
     // var<private> a : array<f32, 0u>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_u)), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_u)),
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: array count (0) must be greater than 0");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Zero) {
     // var<private> a : array<f32, 0i>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_i)), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_i)),
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: array count (0) must be greater than 0");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Negative) {
     // var<private> a : array<f32, -10i>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10_i)), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10_i)),
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: array count (-10) must be greater than 0");
 }
@@ -260,7 +268,7 @@
     // var<private> a : array<f32, size>;
     GlobalConst("size", Expr(0_u));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: array count (0) must be greater than 0");
 }
@@ -270,7 +278,7 @@
     // var<private> a : array<f32, size>;
     GlobalConst("size", Expr(0_i));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: array count (0) must be greater than 0");
 }
@@ -280,14 +288,15 @@
     // var<private> a : array<f32, size>;
     GlobalConst("size", Expr(-10_i));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: array count (-10) must be greater than 0");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
     // var<private> a : array<f32, 10.0>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10_f)), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10_f)),
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
@@ -298,7 +307,7 @@
 TEST_F(ResolverTypeValidationTest, ArraySize_IVecLiteral) {
     // var<private> a : array<f32, vec2<i32>(10, 10)>;
     GlobalVar("a", ty.array(ty.f32(), Call(Source{{12, 34}}, ty.vec2<i32>(), 10_i, 10_i)),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
@@ -311,7 +320,7 @@
     // var<private> a : array<f32, size>;
     GlobalConst("size", Expr(10_f));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
@@ -324,7 +333,7 @@
     // var<private> a : array<f32, size>;
     GlobalConst("size", Call(ty.vec2<i32>(), 100_i, 100_i));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
@@ -335,14 +344,14 @@
 TEST_F(ResolverTypeValidationTest, ArraySize_UnderElementCountLimit) {
     // var<private> a : array<f32, 65535>;
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 65535_a)),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_OverElementCountLimit) {
     // var<private> a : array<f32, 65536>;
     GlobalVar(Source{{56, 78}}, "a", ty.array(Source{{12, 34}}, ty.f32(), Expr(65536_a)),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(12:34 error: array count (65536) must be less than 65536
 56:78 note: while instantiating 'var' a)");
@@ -351,7 +360,7 @@
 TEST_F(ResolverTypeValidationTest, ArraySize_StorageBufferLargeArray) {
     // var<storage> a : array<f32, 65536>;
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 65536_a)),
-              type::AddressSpace::kStorage, utils::Vector{Binding(0_u), Group(0_u)});
+              builtin::AddressSpace::kStorage, utils::Vector{Binding(0_u), Group(0_u)});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
@@ -362,7 +371,7 @@
     // var<storage> a : S;
     Structure("S", utils::Vector{Member(Source{{12, 34}}, "a",
                                         ty.array(Source{{12, 20}}, ty.f32(), 65536_a))});
-    GlobalVar("a", ty(Source{{12, 30}}, "S"), type::AddressSpace::kStorage,
+    GlobalVar("a", ty(Source{{12, 30}}, "S"), builtin::AddressSpace::kStorage,
               utils::Vector{Binding(0_u), Group(0_u)});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -375,7 +384,7 @@
     Structure("S", utils::Vector{Member(Source{{12, 34}}, "a", ty.f32(),
                                         utils::Vector{MemberOffset(800000_a)})});
     GlobalVar("a", ty.array(ty(Source{{12, 30}}, "S"), Expr(Source{{12, 34}}, 65535_a)),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: array byte size (0xc34f7cafc) must not exceed 0xffffffff bytes");
@@ -385,7 +394,7 @@
     // var<private> a : @stride(8000000) array<f32, 65535>;
     GlobalVar("a",
               ty.array(ty.f32(), Expr(Source{{12, 34}}, 65535_a), utils::Vector{Stride(8000000)}),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: array byte size (0x7a1185ee00) must not exceed 0xffffffff bytes");
@@ -395,7 +404,7 @@
     // override size = 10i;
     // var<private> a : array<f32, size>;
     Override("size", Expr(10_i));
-    GlobalVar("a", ty.array(Source{{12, 34}}, ty.f32(), "size"), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.array(Source{{12, 34}}, ty.f32(), "size"), builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: array with an 'override' element count can only be used as the store "
@@ -407,7 +416,7 @@
     // var<workgroup> a : array<array<f32, size>, 4>;
     Override("size", Expr(10_i));
     GlobalVar("a", ty.array(ty.array(Source{{12, 34}}, ty.f32(), "size"), 4_a),
-              type::AddressSpace::kWorkgroup);
+              builtin::AddressSpace::kWorkgroup);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: array with an 'override' element count can only be used as the store "
@@ -466,7 +475,7 @@
     //   var a = w;
     // }
     Override("size", Expr(10_i));
-    GlobalVar("w", ty.array(ty.f32(), "size"), type::AddressSpace::kWorkgroup);
+    GlobalVar("w", ty.array(ty.f32(), "size"), builtin::AddressSpace::kWorkgroup);
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Var("a", Expr(Source{{12, 34}}, "w"))),
@@ -484,7 +493,7 @@
     //   let a = w;
     // }
     Override("size", Expr(10_i));
-    GlobalVar("w", ty.array(ty.f32(), "size"), type::AddressSpace::kWorkgroup);
+    GlobalVar("w", ty.array(ty.f32(), "size"), builtin::AddressSpace::kWorkgroup);
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("a", Expr(Source{{12, 34}}, "w"))),
@@ -503,8 +512,8 @@
     //   a = b;
     // }
     Override("size", Expr(10_i));
-    GlobalVar("a", ty.array(ty.f32(), Add("size", 1_i)), type::AddressSpace::kWorkgroup);
-    GlobalVar("b", ty.array(ty.f32(), Add("size", 1_i)), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.array(ty.f32(), Add("size", 1_i)), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("b", ty.array(ty.f32(), Add("size", 1_i)), builtin::AddressSpace::kWorkgroup);
     WrapInFunction(Assign(Source{{12, 34}}, "a", "b"));
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -538,16 +547,16 @@
     // var<workgroup> a : array<f32, size>;
     Override("size", Expr(10_i));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kWorkgroup);
+              builtin::AddressSpace::kWorkgroup);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_ModuleVar) {
     // var<private> size : i32 = 10i;
     // var<private> a : array<f32, size>;
-    GlobalVar("size", ty.i32(), Expr(10_i), type::AddressSpace::kPrivate);
+    GlobalVar("size", ty.i32(), Expr(10_i), builtin::AddressSpace::kPrivate);
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               R"(12:34 error: var 'size' cannot be referenced at module-scope
@@ -704,7 +713,7 @@
     // var<private> a : array<Foo, 4>;
 
     Structure("Foo", utils::Vector{Member("rt", ty.array<f32>())});
-    GlobalVar("v", ty.array(ty(Source{{12, 34}}, "Foo"), 4_u), type::AddressSpace::kPrivate);
+    GlobalVar("v", ty.array(ty(Source{{12, 34}}, "Foo"), 4_u), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve()) << r()->error();
     EXPECT_EQ(r()->error(),
@@ -750,7 +759,7 @@
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayAsGlobalVariable) {
     GlobalVar(Source{{56, 78}}, "g", ty.array(Source{{12, 34}}, ty.i32()),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -799,7 +808,7 @@
     // fn func(a : ptr<workgroup, array<u32>>) {}
 
     auto* param = Param("a", ty.pointer(Source{{56, 78}}, ty.array(Source{{12, 34}}, ty.i32()),
-                                        type::AddressSpace::kWorkgroup));
+                                        builtin::AddressSpace::kWorkgroup));
 
     Func("func", utils::Vector{param}, ty.void_(),
          utils::Vector{
@@ -864,7 +873,7 @@
 
 TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableType) {
     auto tex_ty = ty.sampled_texture(Source{{12, 34}}, type::TextureDimension::k2d, ty.f32());
-    GlobalVar("arr", ty.array(tex_ty, 4_i), type::AddressSpace::kPrivate);
+    GlobalVar("arr", ty.array(tex_ty, 4_i), builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -872,9 +881,9 @@
 }
 
 TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableTypeWithStride) {
-    auto ptr_ty = ty.pointer<u32>(Source{{12, 34}}, type::AddressSpace::kUniform);
+    auto ptr_ty = ty.pointer<u32>(Source{{12, 34}}, builtin::AddressSpace::kUniform);
     GlobalVar("arr", ty.array(ptr_ty, 4_i, utils::Vector{Stride(16)}),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -1065,8 +1074,8 @@
     // var a : texture_storage_*<r32uint, write>;
     auto& params = GetParam();
 
-    auto st = ty(Source{{12, 34}}, params.name, utils::ToString(type::TexelFormat::kR32Uint),
-                 utils::ToString(type::Access::kWrite));
+    auto st = ty(Source{{12, 34}}, params.name, utils::ToString(builtin::TexelFormat::kR32Uint),
+                 utils::ToString(builtin::Access::kWrite));
 
     GlobalVar("a", st, Group(0_a), Binding(0_a));
 
@@ -1074,7 +1083,7 @@
         EXPECT_TRUE(r()->Resolve()) << r()->error();
     } else {
         EXPECT_FALSE(r()->Resolve());
-        EXPECT_EQ(r()->error(), "12:34 error: unknown type: '" + std::string(params.name) + "'");
+        EXPECT_EQ(r()->error(), "12:34 error: unresolved type '" + std::string(params.name) + "'");
     }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -1082,27 +1091,28 @@
                          testing::ValuesIn(Dimension_cases));
 
 struct FormatParams {
-    type::TexelFormat format;
+    builtin::TexelFormat format;
     bool is_valid;
 };
 
-static constexpr FormatParams format_cases[] = {FormatParams{type::TexelFormat::kBgra8Unorm, true},
-                                                FormatParams{type::TexelFormat::kR32Float, true},
-                                                FormatParams{type::TexelFormat::kR32Sint, true},
-                                                FormatParams{type::TexelFormat::kR32Uint, true},
-                                                FormatParams{type::TexelFormat::kRg32Float, true},
-                                                FormatParams{type::TexelFormat::kRg32Sint, true},
-                                                FormatParams{type::TexelFormat::kRg32Uint, true},
-                                                FormatParams{type::TexelFormat::kRgba16Float, true},
-                                                FormatParams{type::TexelFormat::kRgba16Sint, true},
-                                                FormatParams{type::TexelFormat::kRgba16Uint, true},
-                                                FormatParams{type::TexelFormat::kRgba32Float, true},
-                                                FormatParams{type::TexelFormat::kRgba32Sint, true},
-                                                FormatParams{type::TexelFormat::kRgba32Uint, true},
-                                                FormatParams{type::TexelFormat::kRgba8Sint, true},
-                                                FormatParams{type::TexelFormat::kRgba8Snorm, true},
-                                                FormatParams{type::TexelFormat::kRgba8Uint, true},
-                                                FormatParams{type::TexelFormat::kRgba8Unorm, true}};
+static constexpr FormatParams format_cases[] = {
+    FormatParams{builtin::TexelFormat::kBgra8Unorm, true},
+    FormatParams{builtin::TexelFormat::kR32Float, true},
+    FormatParams{builtin::TexelFormat::kR32Sint, true},
+    FormatParams{builtin::TexelFormat::kR32Uint, true},
+    FormatParams{builtin::TexelFormat::kRg32Float, true},
+    FormatParams{builtin::TexelFormat::kRg32Sint, true},
+    FormatParams{builtin::TexelFormat::kRg32Uint, true},
+    FormatParams{builtin::TexelFormat::kRgba16Float, true},
+    FormatParams{builtin::TexelFormat::kRgba16Sint, true},
+    FormatParams{builtin::TexelFormat::kRgba16Uint, true},
+    FormatParams{builtin::TexelFormat::kRgba32Float, true},
+    FormatParams{builtin::TexelFormat::kRgba32Sint, true},
+    FormatParams{builtin::TexelFormat::kRgba32Uint, true},
+    FormatParams{builtin::TexelFormat::kRgba8Sint, true},
+    FormatParams{builtin::TexelFormat::kRgba8Snorm, true},
+    FormatParams{builtin::TexelFormat::kRgba8Uint, true},
+    FormatParams{builtin::TexelFormat::kRgba8Unorm, true}};
 
 using StorageTextureFormatTest = ResolverTestWithParam<FormatParams>;
 TEST_P(StorageTextureFormatTest, All) {
@@ -1117,19 +1127,19 @@
     // var d : texture_storage_3d<*, write>;
 
     auto st_a = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d, params.format,
-                                   type::Access::kWrite);
+                                   builtin::Access::kWrite);
     GlobalVar("a", st_a, Group(0_a), Binding(0_a));
 
     ast::Type st_b =
-        ty.storage_texture(type::TextureDimension::k2d, params.format, type::Access::kWrite);
+        ty.storage_texture(type::TextureDimension::k2d, params.format, builtin::Access::kWrite);
     GlobalVar("b", st_b, Group(0_a), Binding(1_a));
 
-    ast::Type st_c =
-        ty.storage_texture(type::TextureDimension::k2dArray, params.format, type::Access::kWrite);
+    ast::Type st_c = ty.storage_texture(type::TextureDimension::k2dArray, params.format,
+                                        builtin::Access::kWrite);
     GlobalVar("c", st_c, Group(0_a), Binding(2_a));
 
     ast::Type st_d =
-        ty.storage_texture(type::TextureDimension::k3d, params.format, type::Access::kWrite);
+        ty.storage_texture(type::TextureDimension::k3d, params.format, builtin::Access::kWrite);
     GlobalVar("d", st_d, Group(0_a), Binding(3_a));
 
     if (params.is_valid) {
@@ -1176,7 +1186,7 @@
     // var a : texture_storage_1d<r32uint, read_write>;
 
     auto st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d,
-                                 type::TexelFormat::kR32Uint, type::Access::kReadWrite);
+                                 builtin::TexelFormat::kR32Uint, builtin::Access::kReadWrite);
 
     GlobalVar("a", st, Group(0_a), Binding(0_a));
 
@@ -1190,7 +1200,7 @@
     // var a : texture_storage_1d<r32uint, read>;
 
     auto st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d,
-                                 type::TexelFormat::kR32Uint, type::Access::kRead);
+                                 builtin::TexelFormat::kR32Uint, builtin::Access::kRead);
 
     GlobalVar("a", st, Group(0_a), Binding(0_a));
 
@@ -1203,8 +1213,8 @@
     // @group(0) @binding(0)
     // var a : texture_storage_1d<r32uint, write>;
 
-    auto st = ty.storage_texture(type::TextureDimension::k1d, type::TexelFormat::kR32Uint,
-                                 type::Access::kWrite);
+    auto st = ty.storage_texture(type::TextureDimension::k1d, builtin::TexelFormat::kR32Uint,
+                                 builtin::Access::kWrite);
 
     GlobalVar("a", st, Group(0_a), Binding(0_a));
 
@@ -1235,7 +1245,7 @@
 
     ast::Type el_ty = params.elem_ty(*this);
 
-    GlobalVar("a", ty.mat(el_ty, params.columns, params.rows), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.mat(el_ty, params.columns, params.rows), builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -1276,7 +1286,7 @@
     ast::Type el_ty = params.elem_ty(*this);
 
     GlobalVar("a", ty.mat(Source{{12, 34}}, el_ty, params.columns, params.rows),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: matrix element type must be 'f32' or 'f16'");
 }
@@ -1318,7 +1328,7 @@
 
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", ty.vec(params.elem_ty(*this), params.width), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec(params.elem_ty(*this), params.width), builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -1353,7 +1363,7 @@
     Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: vector element type must be 'bool', 'f32', 'f16', 'i32' "
@@ -1450,7 +1460,7 @@
     // var<private> v : f32<true>;
 
     Enable(builtin::Extension::kF16);
-    GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, GetParam(), true));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, ty(Source{{12, 34}}, GetParam(), true));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: type '" + std::string(GetParam()) +
@@ -1464,7 +1474,7 @@
 
     Enable(builtin::Extension::kF16);
     Alias(Source{{56, 78}}, "A", ty(GetParam()));
-    GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, "A", true));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, ty(Source{{12, 34}}, "A", true));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -1517,7 +1527,7 @@
     // var<private> v : S<true>;
 
     Structure(Source{{56, 78}}, "S", utils::Vector{Member("i", ty.i32())});
-    GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, "S", true));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, ty(Source{{12, 34}}, "S", true));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc
index 61e0dad..37fba4c 100644
--- a/src/tint/resolver/uniformity.cc
+++ b/src/tint/resolver/uniformity.cc
@@ -20,6 +20,7 @@
 #include <utility>
 #include <vector>
 
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/resolver/dependency_graph.h"
 #include "src/tint/scope_stack.h"
@@ -33,8 +34,8 @@
 #include "src/tint/sem/loop_statement.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/switch_statement.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/sem/while_statement.h"
 #include "src/tint/utils/block_allocator.h"
@@ -71,7 +72,7 @@
         CallSiteRequiredToBeUniform,
         CallSiteNoRestriction,
     } tag;
-    ast::DiagnosticSeverity severity = ast::DiagnosticSeverity::kUndefined;
+    builtin::DiagnosticSeverity severity = builtin::DiagnosticSeverity::kUndefined;
 };
 
 /// FunctionTag describes a functions effects on uniformity.
@@ -87,7 +88,7 @@
         ParameterContentsRequiredToBeUniform,
         ParameterNoRestriction,
     } tag;
-    ast::DiagnosticSeverity severity = ast::DiagnosticSeverity::kUndefined;
+    builtin::DiagnosticSeverity severity = builtin::DiagnosticSeverity::kUndefined;
 };
 
 /// Node represents a node in the graph of control flow and value nodes within the analysis of a
@@ -257,13 +258,13 @@
     };
 
     /// @returns the RequiredToBeUniform node that corresponds to `severity`
-    Node* RequiredToBeUniform(ast::DiagnosticSeverity severity) {
+    Node* RequiredToBeUniform(builtin::DiagnosticSeverity severity) {
         switch (severity) {
-            case ast::DiagnosticSeverity::kError:
+            case builtin::DiagnosticSeverity::kError:
                 return required_to_be_uniform_error;
-            case ast::DiagnosticSeverity::kWarning:
+            case builtin::DiagnosticSeverity::kWarning:
                 return required_to_be_uniform_warning;
-            case ast::DiagnosticSeverity::kInfo:
+            case builtin::DiagnosticSeverity::kInfo:
                 return required_to_be_uniform_info;
             default:
                 TINT_ASSERT(Resolver, false && "unhandled severity");
@@ -455,7 +456,7 @@
         // Look at which nodes are reachable from "RequiredToBeUniform".
         {
             utils::UniqueVector<Node*, 4> reachable;
-            auto traverse = [&](ast::DiagnosticSeverity severity) {
+            auto traverse = [&](builtin::DiagnosticSeverity severity) {
                 Traverse(current_function_->RequiredToBeUniform(severity), &reachable);
                 if (reachable.Contains(current_function_->may_be_non_uniform)) {
                     MakeError(*current_function_, current_function_->may_be_non_uniform, severity);
@@ -478,11 +479,11 @@
                 }
                 return true;
             };
-            if (!traverse(ast::DiagnosticSeverity::kError)) {
+            if (!traverse(builtin::DiagnosticSeverity::kError)) {
                 return false;
             } else {
-                if (traverse(ast::DiagnosticSeverity::kWarning)) {
-                    traverse(ast::DiagnosticSeverity::kInfo);
+                if (traverse(builtin::DiagnosticSeverity::kWarning)) {
+                    traverse(builtin::DiagnosticSeverity::kInfo);
                 }
             }
         }
@@ -1145,11 +1146,12 @@
                                                    const ast::IdentifierExpression* ident,
                                                    bool load_rule = false) {
         // Helper to check if the entry point attribute of `obj` indicates non-uniformity.
-        auto has_nonuniform_entry_point_attribute = [](auto* obj) {
+        auto has_nonuniform_entry_point_attribute = [&](auto* obj) {
             // Only the num_workgroups and workgroup_id builtins are uniform.
-            if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(obj->attributes)) {
-                if (builtin->builtin == builtin::BuiltinValue::kNumWorkgroups ||
-                    builtin->builtin == builtin::BuiltinValue::kWorkgroupId) {
+            if (auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(obj->attributes)) {
+                auto builtin = builder_->Sem().Get(builtin_attr)->Value();
+                if (builtin == builtin::BuiltinValue::kNumWorkgroups ||
+                    builtin == builtin::BuiltinValue::kWorkgroupId) {
                     return false;
                 }
             }
@@ -1211,7 +1213,7 @@
             [&](const sem::GlobalVariable* global) {
                 // Loads from global read-write variables may be non-uniform.
                 if (global->Declaration()->Is<ast::Var>() &&
-                    global->Access() != type::Access::kRead && load_rule) {
+                    global->Access() != builtin::Access::kRead && load_rule) {
                     node->AddEdge(current_function_->may_be_non_uniform);
                 } else {
                     node->AddEdge(cf);
@@ -1228,7 +1230,7 @@
                         // We are loading from the pointer, so add an edge to its contents.
                         auto* root = var_user->RootIdentifier();
                         if (root->Is<sem::GlobalVariable>()) {
-                            if (root->Access() != type::Access::kRead) {
+                            if (root->Access() != builtin::Access::kRead) {
                                 // The contents of a mutable global variable is always non-uniform.
                                 node->AddEdge(current_function_->may_be_non_uniform);
                             }
@@ -1473,7 +1475,7 @@
 
                 auto* root = sem_arg->RootIdentifier();
                 if (root->Is<sem::GlobalVariable>()) {
-                    if (root->Access() != type::Access::kRead) {
+                    if (root->Access() != builtin::Access::kRead) {
                         // The contents of a mutable global variable is always non-uniform.
                         arg_contents->AddEdge(current_function_->may_be_non_uniform);
                     }
@@ -1497,8 +1499,8 @@
         result->type = Node::kFunctionCallReturnValue;
         Node* cf_after = CreateNode({"CF_after_", name}, call);
 
-        auto default_severity = kUniformityFailuresAsError ? ast::DiagnosticSeverity::kError
-                                                           : ast::DiagnosticSeverity::kWarning;
+        auto default_severity = kUniformityFailuresAsError ? builtin::DiagnosticSeverity::kError
+                                                           : builtin::DiagnosticSeverity::kWarning;
 
         // Get tags for the callee.
         CallSiteTag callsite_tag = {CallSiteTag::CallSiteNoRestriction};
@@ -1519,9 +1521,9 @@
                            builtin->Type() == sem::BuiltinType::kTextureSampleBias ||
                            builtin->Type() == sem::BuiltinType::kTextureSampleCompare) {
                     // Get the severity of derivative uniformity violations in this context.
-                    auto severity =
-                        sem_.DiagnosticSeverity(call, ast::DiagnosticRule::kDerivativeUniformity);
-                    if (severity != ast::DiagnosticSeverity::kOff) {
+                    auto severity = sem_.DiagnosticSeverity(
+                        call, builtin::DiagnosticRule::kDerivativeUniformity);
+                    if (severity != builtin::DiagnosticSeverity::kOff) {
                         callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, severity};
                     }
                     function_tag = ReturnValueMayBeNonUniform;
@@ -1539,11 +1541,11 @@
                 function_tag = info->function_tag;
                 func_info = info;
             },
-            [&](const sem::TypeInitializer*) {
+            [&](const sem::ValueConstructor*) {
                 callsite_tag = {CallSiteTag::CallSiteNoRestriction};
                 function_tag = NoRestriction;
             },
-            [&](const sem::TypeConversion*) {
+            [&](const sem::ValueConversion*) {
                 callsite_tag = {CallSiteTag::CallSiteNoRestriction};
                 function_tag = NoRestriction;
             },
@@ -1629,7 +1631,7 @@
                     current_function_->RequiredToBeUniform(default_severity)->AddEdge(args[i]);
                 } else {
                     // All other builtin function parameters are RequiredToBeUniformForReturnValue,
-                    // as are parameters for type initializers and type conversions.
+                    // as are parameters for value constructors and value conversions.
                     result->AddEdge(args[i]);
                 }
             }
@@ -1686,8 +1688,9 @@
 
     /// Recursively descend through the function called by `call` and the functions that it calls in
     /// order to find a call to a builtin function that requires uniformity with the given severity.
-    const ast::CallExpression* FindBuiltinThatRequiresUniformity(const ast::CallExpression* call,
-                                                                 ast::DiagnosticSeverity severity) {
+    const ast::CallExpression* FindBuiltinThatRequiresUniformity(
+        const ast::CallExpression* call,
+        builtin::DiagnosticSeverity severity) {
         auto* target = SemCall(call)->Target();
         if (target->Is<sem::Builtin>()) {
             // This is a call to a builtin, so we must be done.
@@ -1749,11 +1752,11 @@
 
         auto var_type = [&](const sem::Variable* var) {
             switch (var->AddressSpace()) {
-                case type::AddressSpace::kStorage:
+                case builtin::AddressSpace::kStorage:
                     return "read_write storage buffer ";
-                case type::AddressSpace::kWorkgroup:
+                case builtin::AddressSpace::kWorkgroup:
                     return "workgroup storage variable ";
-                case type::AddressSpace::kPrivate:
+                case builtin::AddressSpace::kPrivate:
                     return "module-scope private variable ";
                 default:
                     return "";
@@ -1848,11 +1851,13 @@
     /// @param function the function that the diagnostic is being produced for
     /// @param source_node the node that has caused a uniformity issue in `function`
     /// @param severity the severity of the diagnostic
-    void MakeError(FunctionInfo& function, Node* source_node, ast::DiagnosticSeverity severity) {
+    void MakeError(FunctionInfo& function,
+                   Node* source_node,
+                   builtin::DiagnosticSeverity severity) {
         // Helper to produce a diagnostic message, as a note or with the global failure severity.
         auto report = [&](Source source, std::string msg, bool note) {
             diag::Diagnostic error{};
-            error.severity = note ? diag::Severity::Note : ast::ToSeverity(severity);
+            error.severity = note ? diag::Severity::Note : builtin::ToSeverity(severity);
             error.system = diag::System::Resolver;
             error.source = source;
             error.message = msg;
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index fbd0912..fec74b3 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -168,14 +168,14 @@
     }
 
     /// Convert a function call to its string representation.
-    static std::string FunctionToStr(Function f) {
+    static std::string FunctionCallToStr(Function f) {
         switch (f) {
             case kUserNoRestriction:
                 return "user_no_restriction()";
             case kMin:
-                return "min(1, 1)";
+                return "_ = min(1, 1)";
             case kTextureSampleLevel:
-                return "textureSampleLevel(t, s, vec2(0.5, 0.5), 0.0)";
+                return "_ = textureSampleLevel(t, s, vec2(0.5, 0.5), 0.0)";
             case kUserRequiredToBeUniform:
                 return "user_required_to_be_uniform()";
             case kWorkgroupBarrier:
@@ -183,31 +183,31 @@
             case kStorageBarrier:
                 return "storageBarrier()";
             case kWorkgroupUniformLoad:
-                return "workgroupUniformLoad(&w)";
+                return "_ = workgroupUniformLoad(&w)";
             case kTextureSample:
-                return "textureSample(t, s, vec2(0.5, 0.5))";
+                return "_ = textureSample(t, s, vec2(0.5, 0.5))";
             case kTextureSampleBias:
-                return "textureSampleBias(t, s, vec2(0.5, 0.5), 2.0)";
+                return "_ = textureSampleBias(t, s, vec2(0.5, 0.5), 2.0)";
             case kTextureSampleCompare:
-                return "textureSampleCompare(td, sc, vec2(0.5, 0.5), 0.5)";
+                return "_ = textureSampleCompare(td, sc, vec2(0.5, 0.5), 0.5)";
             case kDpdx:
-                return "dpdx(1.0)";
+                return "_ = dpdx(1.0)";
             case kDpdxCoarse:
-                return "dpdxCoarse(1.0)";
+                return "_ = dpdxCoarse(1.0)";
             case kDpdxFine:
-                return "dpdxFine(1.0)";
+                return "_ = dpdxFine(1.0)";
             case kDpdy:
-                return "dpdy(1.0)";
+                return "_ = dpdy(1.0)";
             case kDpdyCoarse:
-                return "dpdyCoarse(1.0)";
+                return "_ = dpdyCoarse(1.0)";
             case kDpdyFine:
-                return "dpdyFine(1.0)";
+                return "_ = dpdyFine(1.0)";
             case kFwidth:
-                return "fwidth(1.0)";
+                return "_ = fwidth(1.0)";
             case kFwidthCoarse:
-                return "fwidthCoarse(1.0)";
+                return "_ = fwidthCoarse(1.0)";
             case kFwidthFine:
-                return "fwidthFine(1.0)";
+                return "_ = fwidthFine(1.0)";
             case kEndOfFunctionRange:
                 return "<invalid>";
         }
@@ -314,7 +314,7 @@
 
   if ()" + ConditionToStr(condition) +
                       R"() {
-    )" + FunctionToStr(function) +
+    )" + FunctionCallToStr(function) +
                       R"(;
   }
 }
@@ -610,7 +610,7 @@
 fn main(@builtin()" + GetParam().name +
                       R"() b : )" + GetParam().type + R"() {
   if (u32(vec4(b).x) == 0u) {
-    dpdx(0.5);
+    _ = dpdx(0.5);
   }
 }
 )";
@@ -619,9 +619,9 @@
     RunTest(src, should_pass);
     if (!should_pass) {
         EXPECT_EQ(error_,
-                  R"(test:5:5 error: 'dpdx' must only be called from uniform control flow
-    dpdx(0.5);
-    ^^^^
+                  R"(test:5:9 error: 'dpdx' must only be called from uniform control flow
+    _ = dpdx(0.5);
+        ^^^^^^^^^
 
 test:4:3 note: control flow depends on possibly non-uniform value
   if (u32(vec4(b).x) == 0u) {
@@ -644,7 +644,7 @@
 @fragment
 fn main(s : S) {
   if (u32(vec4(s.b).x) == 0u) {
-    dpdx(0.5);
+    _ = dpdx(0.5);
   }
 }
 )";
@@ -653,9 +653,9 @@
     RunTest(src, should_pass);
     if (!should_pass) {
         EXPECT_EQ(error_,
-                  R"(test:9:5 error: 'dpdx' must only be called from uniform control flow
-    dpdx(0.5);
-    ^^^^
+                  R"(test:9:9 error: 'dpdx' must only be called from uniform control flow
+    _ = dpdx(0.5);
+        ^^^^^^^^^
 
 test:8:3 note: control flow depends on possibly non-uniform value
   if (u32(vec4(s.b).x) == 0u) {
@@ -683,16 +683,16 @@
 @fragment
 fn main(@location(0) l : f32) {
   if (l == 0.0) {
-    dpdx(0.5);
+    _ = dpdx(0.5);
   }
 }
 )";
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:5:5 error: 'dpdx' must only be called from uniform control flow
-    dpdx(0.5);
-    ^^^^
+              R"(test:5:9 error: 'dpdx' must only be called from uniform control flow
+    _ = dpdx(0.5);
+        ^^^^^^^^^
 
 test:4:3 note: control flow depends on possibly non-uniform value
   if (l == 0.0) {
@@ -713,16 +713,16 @@
 @fragment
 fn main(s : S) {
   if (s.l == 0.0) {
-    dpdx(0.5);
+    _ = dpdx(0.5);
   }
 }
 )";
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:9:5 error: 'dpdx' must only be called from uniform control flow
-    dpdx(0.5);
-    ^^^^
+              R"(test:9:9 error: 'dpdx' must only be called from uniform control flow
+    _ = dpdx(0.5);
+        ^^^^^^^^^
 
 test:8:3 note: control flow depends on possibly non-uniform value
   if (s.l == 0.0) {
@@ -5301,8 +5301,8 @@
     }
     foo_body.Push(b.Decl(b.Let("rhs", rhs_init)));
     for (int i = 0; i < 255; i++) {
-        params.Push(
-            b.Param("p" + std::to_string(i), ty.pointer(ty.i32(), type::AddressSpace::kFunction)));
+        params.Push(b.Param("p" + std::to_string(i),
+                            ty.pointer(ty.i32(), builtin::AddressSpace::kFunction)));
         if (i > 0) {
             foo_body.Push(b.Assign(b.Deref("p" + std::to_string(i)), "rhs"));
         }
@@ -5321,7 +5321,7 @@
     //     workgroupBarrier();
     //   }
     // }
-    b.GlobalVar("non_uniform_global", ty.i32(), type::AddressSpace::kPrivate);
+    b.GlobalVar("non_uniform_global", ty.i32(), builtin::AddressSpace::kPrivate);
     utils::Vector<const ast::Statement*, 8> main_body;
     utils::Vector<const ast::Expression*, 8> args;
     for (int i = 0; i < 255; i++) {
@@ -7847,7 +7847,7 @@
     //     workgroupBarrier();
     //   }
     // }
-    b.GlobalVar("v0", ty.i32(), type::AddressSpace::kPrivate, b.Expr(0_i));
+    b.GlobalVar("v0", ty.i32(), builtin::AddressSpace::kPrivate, b.Expr(0_i));
     utils::Vector<const ast::Statement*, 8> foo_body;
     std::string v_last = "v0";
     for (int i = 1; i < 100000; i++) {
@@ -7871,16 +7871,16 @@
 
 class UniformityAnalysisDiagnosticFilterTest
     : public UniformityAnalysisTestBase,
-      public ::testing::TestWithParam<ast::DiagnosticSeverity> {
+      public ::testing::TestWithParam<builtin::DiagnosticSeverity> {
   protected:
     // TODO(jrprice): Remove this in favour of utils::ToString() when we change "note" to "info".
-    const char* ToStr(ast::DiagnosticSeverity severity) {
+    const char* ToStr(builtin::DiagnosticSeverity severity) {
         switch (severity) {
-            case ast::DiagnosticSeverity::kError:
+            case builtin::DiagnosticSeverity::kError:
                 return "error";
-            case ast::DiagnosticSeverity::kWarning:
+            case builtin::DiagnosticSeverity::kWarning:
                 return "warning";
-            case ast::DiagnosticSeverity::kInfo:
+            case builtin::DiagnosticSeverity::kInfo:
                 return "note";
             default:
                 return "<undefined>";
@@ -7904,9 +7904,9 @@
 }
 )";
 
-    RunTest(ss.str(), param != ast::DiagnosticSeverity::kError);
+    RunTest(ss.str(), param != builtin::DiagnosticSeverity::kError);
 
-    if (param == ast::DiagnosticSeverity::kOff) {
+    if (param == builtin::DiagnosticSeverity::kOff) {
         EXPECT_TRUE(error_.empty());
     } else {
         std::ostringstream err;
@@ -7932,8 +7932,8 @@
 }
 )";
 
-    RunTest(ss.str(), param != ast::DiagnosticSeverity::kError);
-    if (param == ast::DiagnosticSeverity::kOff) {
+    RunTest(ss.str(), param != builtin::DiagnosticSeverity::kError);
+    if (param == builtin::DiagnosticSeverity::kOff) {
         EXPECT_TRUE(error_.empty());
     } else {
         std::ostringstream err;
@@ -7958,8 +7958,8 @@
 }
 )";
 
-    RunTest(ss.str(), param != ast::DiagnosticSeverity::kError);
-    if (param == ast::DiagnosticSeverity::kOff) {
+    RunTest(ss.str(), param != builtin::DiagnosticSeverity::kError);
+    if (param == builtin::DiagnosticSeverity::kOff) {
         EXPECT_TRUE(error_.empty());
     } else {
         std::ostringstream err;
@@ -7970,10 +7970,10 @@
 
 INSTANTIATE_TEST_SUITE_P(UniformityAnalysisTest,
                          UniformityAnalysisDiagnosticFilterTest,
-                         ::testing::Values(ast::DiagnosticSeverity::kError,
-                                           ast::DiagnosticSeverity::kWarning,
-                                           ast::DiagnosticSeverity::kInfo,
-                                           ast::DiagnosticSeverity::kOff));
+                         ::testing::Values(builtin::DiagnosticSeverity::kError,
+                                           builtin::DiagnosticSeverity::kWarning,
+                                           builtin::DiagnosticSeverity::kInfo,
+                                           builtin::DiagnosticSeverity::kOff));
 
 TEST_F(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction_CalledByAnotherFunction) {
     std::string src = R"(
@@ -7981,7 +7981,7 @@
 
 @diagnostic(info, derivative_uniformity)
 fn bar() {
-  dpdx(1.0);
+  _ = dpdx(1.0);
 }
 
 fn foo() {
@@ -8002,7 +8002,7 @@
 @diagnostic(info, derivative_uniformity)
 fn bar(x : i32) {
   if (x == 0) {
-    dpdx(1.0);
+    _ = dpdx(1.0);
   }
 }
 
@@ -8022,7 +8022,7 @@
 @group(0) @binding(0) var<storage, read_write> non_uniform : i32;
 
 fn bar() {
-  dpdx(1.0);
+  _ = dpdx(1.0);
 }
 
 @diagnostic(off, derivative_uniformity)
@@ -8047,44 +8047,44 @@
 
 fn a() {
   if (non_uniform == 42) {
-    dpdx(1.0);
+    _ = dpdx(1.0);
   }
 }
 
 @diagnostic(off, derivative_uniformity)
 fn b() {
   if (non_uniform == 42) {
-    dpdx(1.0);
+    _ = dpdx(1.0);
   }
 }
 
 @diagnostic(info, derivative_uniformity)
 fn c() {
   if (non_uniform == 42) {
-    dpdx(1.0);
+    _ = dpdx(1.0);
   }
 }
 
 @diagnostic(warning, derivative_uniformity)
 fn d() {
   if (non_uniform == 42) {
-    dpdx(1.0);
+    _ = dpdx(1.0);
   }
 }
 
 @diagnostic(error, derivative_uniformity)
 fn e() {
   if (non_uniform == 42) {
-    dpdx(1.0);
+    _ = dpdx(1.0);
   }
 }
 )";
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:8:5 note: 'dpdx' must only be called from uniform control flow
-    dpdx(1.0);
-    ^^^^
+              R"(test:8:9 note: 'dpdx' must only be called from uniform control flow
+    _ = dpdx(1.0);
+        ^^^^^^^^^
 
 test:7:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
@@ -8094,9 +8094,9 @@
   if (non_uniform == 42) {
       ^^^^^^^^^^^
 
-test:22:5 note: 'dpdx' must only be called from uniform control flow
-    dpdx(1.0);
-    ^^^^
+test:22:9 note: 'dpdx' must only be called from uniform control flow
+    _ = dpdx(1.0);
+        ^^^^^^^^^
 
 test:21:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
@@ -8106,9 +8106,9 @@
   if (non_uniform == 42) {
       ^^^^^^^^^^^
 
-test:29:5 warning: 'dpdx' must only be called from uniform control flow
-    dpdx(1.0);
-    ^^^^
+test:29:9 warning: 'dpdx' must only be called from uniform control flow
+    _ = dpdx(1.0);
+        ^^^^^^^^^
 
 test:28:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
@@ -8118,9 +8118,9 @@
   if (non_uniform == 42) {
       ^^^^^^^^^^^
 
-test:36:5 error: 'dpdx' must only be called from uniform control flow
-    dpdx(1.0);
-    ^^^^
+test:36:9 error: 'dpdx' must only be called from uniform control flow
+    _ = dpdx(1.0);
+        ^^^^^^^^^
 
 test:35:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
@@ -8215,7 +8215,7 @@
 
 fn foo() {
   if (non_uniform == 42) {
-    dpdx(1.0);
+    _ = dpdx(1.0);
   }
 }
 
diff --git a/src/tint/resolver/unresolved_identifier_test.cc b/src/tint/resolver/unresolved_identifier_test.cc
new file mode 100644
index 0000000..e52b858
--- /dev/null
+++ b/src/tint/resolver/unresolved_identifier_test.cc
@@ -0,0 +1,108 @@
+// Copyright 2023 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 "gmock/gmock.h"
+
+#include "src/tint/resolver/resolver_test_helper.h"
+
+using namespace tint::number_suffixes;  // NOLINT
+
+namespace tint::resolver {
+namespace {
+
+using ResolverUnresolvedIdentifierSuggestions = ResolverTest;
+
+TEST_F(ResolverUnresolvedIdentifierSuggestions, AddressSpace) {
+    AST().AddGlobalVariable(create<ast::Var>(
+        Ident("v"),                        // name
+        ty.i32(),                          // type
+        Expr(Source{{12, 34}}, "privte"),  // declared_address_space
+        nullptr,                           // declared_access
+        nullptr,                           // initializer
+        utils::Empty                       // attributes
+        ));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved address space 'privte'
+12:34 note: Did you mean 'private'?
+Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
+}
+
+TEST_F(ResolverUnresolvedIdentifierSuggestions, BuiltinValue) {
+    Func("f",
+         utils::Vector{
+             Param("p", ty.i32(), utils::Vector{Builtin(Expr(Source{{12, 34}}, "positon"))})},
+         ty.void_(), utils::Empty);
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved builtin value 'positon'
+12:34 note: Did you mean 'position'?
+Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
+}
+
+TEST_F(ResolverUnresolvedIdentifierSuggestions, TexelFormat) {
+    GlobalVar("v", ty("texture_storage_1d", Expr(Source{{12, 34}}, "rba8unorm"), "read"));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved texel format 'rba8unorm'
+12:34 note: Did you mean 'rgba8unorm'?
+Possible values: 'bgra8unorm', 'r32float', 'r32sint', 'r32uint', 'rg32float', 'rg32sint', 'rg32uint', 'rgba16float', 'rgba16sint', 'rgba16uint', 'rgba32float', 'rgba32sint', 'rgba32uint', 'rgba8sint', 'rgba8snorm', 'rgba8uint', 'rgba8unorm')");
+}
+
+TEST_F(ResolverUnresolvedIdentifierSuggestions, AccessMode) {
+    AST().AddGlobalVariable(create<ast::Var>(Ident("v"),       // name
+                                             ty.i32(),         // type
+                                             Expr("private"),  // declared_address_space
+                                             Expr(Source{{12, 34}}, "reed"),  // declared_access
+                                             nullptr,                         // initializer
+                                             utils::Empty                     // attributes
+                                             ));
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved access 'reed'
+12:34 note: Did you mean 'read'?
+Possible values: 'read', 'read_write', 'write')");
+}
+
+TEST_F(ResolverUnresolvedIdentifierSuggestions, InterpolationSampling) {
+    Structure("s", utils::Vector{
+                       Member("m", ty.vec4<f32>(),
+                              utils::Vector{
+                                  Interpolate(builtin::InterpolationType::kLinear,
+                                              Expr(Source{{12, 34}}, "centre")),
+                              }),
+                   });
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved interpolation sampling 'centre'
+12:34 note: Did you mean 'center'?
+Possible values: 'center', 'centroid', 'sample')");
+}
+
+TEST_F(ResolverUnresolvedIdentifierSuggestions, InterpolationType) {
+    Structure("s", utils::Vector{
+                       Member("m", ty.vec4<f32>(),
+                              utils::Vector{
+                                  Interpolate(Expr(Source{{12, 34}}, "liner")),
+                              }),
+                   });
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved interpolation type 'liner'
+12:34 note: Did you mean 'linear'?
+Possible values: 'flat', 'linear', 'perspective')");
+}
+
+}  // namespace
+}  // namespace tint::resolver
diff --git a/src/tint/resolver/validation_test.cc b/src/tint/resolver/validation_test.cc
index 73fa9b8..6485a6a 100644
--- a/src/tint/resolver/validation_test.cc
+++ b/src/tint/resolver/validation_test.cc
@@ -30,6 +30,7 @@
 #include "src/tint/ast/switch_statement.h"
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/function.h"
@@ -62,8 +63,8 @@
 };
 
 TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInVertexStage) {
-    GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("dst", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("dst", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
     auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
 
     Func(Source{{9, 10}}, "f0", utils::Empty, ty.vec4<f32>(),
@@ -94,8 +95,8 @@
     //  f1();
     //}
 
-    GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("dst", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("dst", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
     auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
 
     Func(Source{{5, 6}}, "f2", utils::Empty, ty.void_(), utils::Vector{stmt});
@@ -167,7 +168,7 @@
     WrapInFunction(assign);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: unknown identifier: 'b')");
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved identifier 'b')");
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariableInBlockStatement_Fail) {
@@ -182,7 +183,7 @@
     WrapInFunction(body);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: unknown identifier: 'b')");
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved identifier 'b')");
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariableGlobalVariable_Pass) {
@@ -192,7 +193,7 @@
     //   return;
     // }
 
-    GlobalVar("global_var", ty.f32(), type::AddressSpace::kPrivate, Expr(2.1_f));
+    GlobalVar("global_var", ty.f32(), builtin::AddressSpace::kPrivate, Expr(2.1_f));
 
     Func("my_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -222,7 +223,7 @@
     WrapInFunction(outer_body);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: unknown identifier: 'a')");
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved identifier 'a')");
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariableOuterScope_Pass) {
@@ -262,11 +263,11 @@
     WrapInFunction(outer_body);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: unknown identifier: 'a')");
+    EXPECT_EQ(r()->error(), R"(12:34 error: unresolved identifier 'a')");
 }
 
 TEST_F(ResolverValidationTest, AddressSpace_FunctionVariableWorkgroupClass) {
-    auto* var = Var("var", ty.i32(), type::AddressSpace::kWorkgroup);
+    auto* var = Var("var", ty.i32(), builtin::AddressSpace::kWorkgroup);
 
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -280,7 +281,7 @@
 }
 
 TEST_F(ResolverValidationTest, AddressSpace_FunctionVariableI32) {
-    auto* var = Var("s", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = Var("s", ty.i32(), builtin::AddressSpace::kPrivate);
 
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -295,26 +296,29 @@
 
 TEST_F(ResolverValidationTest, AddressSpace_SamplerExplicitAddressSpace) {
     auto t = ty.sampler(type::SamplerKind::kSampler);
-    GlobalVar(Source{{12, 34}}, "var", t, type::AddressSpace::kHandle, Binding(0_a), Group(0_a));
+    GlobalVar(Source{{12, 34}}, "var", t, builtin::AddressSpace::kPrivate, Binding(0_a),
+              Group(0_a));
 
     EXPECT_FALSE(r()->Resolve());
 
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: variables of type 'sampler' must not have a address space)");
+              R"(12:34 error: variables of type 'sampler' must not specifiy an address space)");
 }
 
 TEST_F(ResolverValidationTest, AddressSpace_TextureExplicitAddressSpace) {
     auto t = ty.sampled_texture(type::TextureDimension::k1d, ty.f32());
-    GlobalVar(Source{{12, 34}}, "var", t, type::AddressSpace::kHandle, Binding(0_a), Group(0_a));
+    GlobalVar(Source{{12, 34}}, "var", t, builtin::AddressSpace::kFunction, Binding(0_a),
+              Group(0_a));
 
     EXPECT_FALSE(r()->Resolve()) << r()->error();
 
-    EXPECT_EQ(r()->error(),
-              R"(12:34 error: variables of type 'texture_1d<f32>' must not have a address space)");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: variables of type 'texture_1d<f32>' must not specifiy an address space)");
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
-    GlobalVar("my_vec", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* mem = MemberAccessor("my_vec", Ident(Source{{{3, 3}, {3, 7}}}, "xyqz"));
     WrapInFunction(mem);
@@ -324,7 +328,7 @@
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
-    GlobalVar("my_vec", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* mem = MemberAccessor("my_vec", Ident(Source{{{3, 3}, {3, 7}}}, "rgyw"));
     WrapInFunction(mem);
@@ -335,7 +339,7 @@
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
-    GlobalVar("my_vec", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* mem = MemberAccessor("my_vec", Ident(Source{{{3, 3}, {3, 8}}}, "zzzzz"));
     WrapInFunction(mem);
@@ -345,7 +349,7 @@
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) {
-    GlobalVar("my_vec", ty.vec2<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* mem = MemberAccessor("my_vec", Ident(Source{{3, 3}}, "z"));
     WrapInFunction(mem);
@@ -376,7 +380,7 @@
     //     let x: f32 = (*p).z;
     //     return x;
     // }
-    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kFunction));
+    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kFunction));
     auto* star_p = Deref(p);
     auto* accessor_expr = MemberAccessor(star_p, "z");
     auto* x = Var("x", ty.f32(), accessor_expr);
@@ -393,7 +397,7 @@
     //     let x: f32 = *p.z;
     //     return x;
     // }
-    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kFunction));
+    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kFunction));
     auto* accessor_expr = MemberAccessor(p, Ident(Source{{12, 34}}, "z"));
     auto* star_p = Deref(accessor_expr);
     auto* x = Var("x", ty.f32(), star_p);
@@ -1230,8 +1234,9 @@
 
 TEST_F(ResolverTest, Expr_Initializer_Cast_Pointer) {
     auto* vf = Var("vf", ty.f32());
-    auto* c = Call(Source{{12, 34}}, ty.pointer<i32>(type::AddressSpace::kFunction), ExprList(vf));
-    auto* ip = Let("ip", ty.pointer<i32>(type::AddressSpace::kFunction), c);
+    auto* c =
+        Call(Source{{12, 34}}, ty.pointer<i32>(builtin::AddressSpace::kFunction), ExprList(vf));
+    auto* ip = Let("ip", ty.pointer<i32>(builtin::AddressSpace::kFunction), c);
     WrapInFunction(Decl(vf), Decl(ip));
 
     EXPECT_FALSE(r()->Resolve());
@@ -1239,21 +1244,22 @@
 }
 
 TEST_F(ResolverTest, I32_Overflow) {
-    GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate, Expr(Source{{12, 24}}, 2147483648_a));
+    GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate, Expr(Source{{12, 24}}, 2147483648_a));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(12:24 error: value 2147483648 cannot be represented as 'i32')");
 }
 
 TEST_F(ResolverTest, I32_Underflow) {
-    GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate, Expr(Source{{12, 24}}, -2147483649_a));
+    GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate,
+              Expr(Source{{12, 24}}, -2147483649_a));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(12:24 error: value -2147483649 cannot be represented as 'i32')");
 }
 
 TEST_F(ResolverTest, U32_Overflow) {
-    GlobalVar("v", ty.u32(), type::AddressSpace::kPrivate, Expr(Source{{12, 24}}, 4294967296_a));
+    GlobalVar("v", ty.u32(), builtin::AddressSpace::kPrivate, Expr(Source{{12, 24}}, 4294967296_a));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(12:24 error: value 4294967296 cannot be represented as 'u32')");
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index 44d6c5b..b272b15 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -49,8 +49,8 @@
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/switch_statement.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/sem/while_statement.h"
 #include "src/tint/type/abstract_numeric.h"
@@ -88,25 +88,25 @@
     }
 }
 
-bool IsValidStorageTextureTexelFormat(type::TexelFormat format) {
+bool IsValidStorageTextureTexelFormat(builtin::TexelFormat format) {
     switch (format) {
-        case type::TexelFormat::kBgra8Unorm:
-        case type::TexelFormat::kR32Uint:
-        case type::TexelFormat::kR32Sint:
-        case type::TexelFormat::kR32Float:
-        case type::TexelFormat::kRg32Uint:
-        case type::TexelFormat::kRg32Sint:
-        case type::TexelFormat::kRg32Float:
-        case type::TexelFormat::kRgba8Unorm:
-        case type::TexelFormat::kRgba8Snorm:
-        case type::TexelFormat::kRgba8Uint:
-        case type::TexelFormat::kRgba8Sint:
-        case type::TexelFormat::kRgba16Uint:
-        case type::TexelFormat::kRgba16Sint:
-        case type::TexelFormat::kRgba16Float:
-        case type::TexelFormat::kRgba32Uint:
-        case type::TexelFormat::kRgba32Sint:
-        case type::TexelFormat::kRgba32Float:
+        case builtin::TexelFormat::kBgra8Unorm:
+        case builtin::TexelFormat::kR32Uint:
+        case builtin::TexelFormat::kR32Sint:
+        case builtin::TexelFormat::kR32Float:
+        case builtin::TexelFormat::kRg32Uint:
+        case builtin::TexelFormat::kRg32Sint:
+        case builtin::TexelFormat::kRg32Float:
+        case builtin::TexelFormat::kRgba8Unorm:
+        case builtin::TexelFormat::kRgba8Snorm:
+        case builtin::TexelFormat::kRgba8Uint:
+        case builtin::TexelFormat::kRgba8Sint:
+        case builtin::TexelFormat::kRgba16Uint:
+        case builtin::TexelFormat::kRgba16Sint:
+        case builtin::TexelFormat::kRgba16Float:
+        case builtin::TexelFormat::kRgba32Uint:
+        case builtin::TexelFormat::kRgba32Sint:
+        case builtin::TexelFormat::kRgba32Float:
             return true;
         default:
             return false;
@@ -114,15 +114,11 @@
 }
 
 // Helper to stringify a pipeline IO attribute.
-std::string attr_to_str(const ast::Attribute* attr,
-                        std::optional<uint32_t> location = std::nullopt) {
-    std::stringstream str;
-    if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
-        str << "builtin(" << builtin->builtin << ")";
-    } else if (attr->Is<ast::LocationAttribute>()) {
-        str << "location(" << location.value() << ")";
-    }
-    return str.str();
+std::string AttrToStr(const ast::Attribute* attr) {
+    return Switch(
+        attr,  //
+        [&](const ast::BuiltinAttribute*) { return "@builtin"; },
+        [&](const ast::LocationAttribute*) { return "@location"; });
 }
 
 template <typename CALLBACK>
@@ -159,10 +155,10 @@
       atomic_composite_info_(atomic_composite_info),
       valid_type_storage_layouts_(valid_type_storage_layouts) {
     // Set default severities for filterable diagnostic rules.
-    diagnostic_filters_.Set(ast::DiagnosticRule::kDerivativeUniformity,
-                            ast::DiagnosticSeverity::kError);
-    diagnostic_filters_.Set(ast::DiagnosticRule::kChromiumUnreachableCode,
-                            ast::DiagnosticSeverity::kWarning);
+    diagnostic_filters_.Set(builtin::DiagnosticRule::kDerivativeUniformity,
+                            builtin::DiagnosticSeverity::kError);
+    diagnostic_filters_.Set(builtin::DiagnosticRule::kChromiumUnreachableCode,
+                            builtin::DiagnosticSeverity::kWarning);
 }
 
 Validator::~Validator() = default;
@@ -179,18 +175,18 @@
     diagnostics_.add_note(diag::System::Resolver, msg, source);
 }
 
-bool Validator::AddDiagnostic(ast::DiagnosticRule rule,
+bool Validator::AddDiagnostic(builtin::DiagnosticRule rule,
                               const std::string& msg,
                               const Source& source) const {
     auto severity = diagnostic_filters_.Get(rule);
-    if (severity != ast::DiagnosticSeverity::kOff) {
+    if (severity != builtin::DiagnosticSeverity::kOff) {
         diag::Diagnostic d{};
         d.severity = ToSeverity(severity);
         d.system = diag::System::Resolver;
         d.source = source;
         d.message = msg;
         diagnostics_.add(std::move(d));
-        if (severity == ast::DiagnosticSeverity::kError) {
+        if (severity == builtin::DiagnosticSeverity::kError) {
             return false;
         }
     }
@@ -288,7 +284,7 @@
 }
 
 bool Validator::Pointer(const ast::TemplatedIdentifier* a, const type::Pointer* s) const {
-    if (s->AddressSpace() == type::AddressSpace::kUndefined) {
+    if (s->AddressSpace() == builtin::AddressSpace::kUndefined) {
         AddError("ptr missing address space", a->source);
         return false;
     }
@@ -298,8 +294,8 @@
         // When writing a variable declaration or a pointer type in WGSL source:
         // * For the storage address space, the access mode is optional, and defaults to read.
         // * For other address spaces, the access mode must not be written.
-        if (s->AddressSpace() != type::AddressSpace::kStorage) {
-            AddError("only pointers in <storage> address space may declare an access mode",
+        if (s->AddressSpace() != builtin::AddressSpace::kStorage) {
+            AddError("only pointers in <storage> address space may specify an access mode",
                      a->source);
             return false;
         }
@@ -311,9 +307,9 @@
 
 bool Validator::StorageTexture(const type::StorageTexture* t, const Source& source) const {
     switch (t->access()) {
-        case type::Access::kWrite:
+        case builtin::Access::kWrite:
             break;
-        case type::Access::kUndefined:
+        case builtin::Access::kUndefined:
             AddError("storage texture missing access control", source);
             return false;
         default:
@@ -373,7 +369,7 @@
 }
 
 bool Validator::VariableInitializer(const ast::Variable* v,
-                                    type::AddressSpace address_space,
+                                    builtin::AddressSpace address_space,
                                     const type::Type* storage_ty,
                                     const sem::ValueExpression* initializer) const {
     auto* initializer_ty = initializer->Type();
@@ -390,8 +386,8 @@
 
     if (v->Is<ast::Var>()) {
         switch (address_space) {
-            case type::AddressSpace::kPrivate:
-            case type::AddressSpace::kFunction:
+            case builtin::AddressSpace::kPrivate:
+            case builtin::AddressSpace::kFunction:
                 break;  // Allowed an initializer
             default:
                 // https://gpuweb.github.io/gpuweb/wgsl/#var-and-let
@@ -409,17 +405,17 @@
 }
 
 bool Validator::AddressSpaceLayout(const type::Type* store_ty,
-                                   type::AddressSpace address_space,
+                                   builtin::AddressSpace address_space,
                                    Source source) const {
     // https://gpuweb.github.io/gpuweb/wgsl/#storage-class-layout-constraints
 
     auto is_uniform_struct_or_array = [address_space](const type::Type* ty) {
-        return address_space == type::AddressSpace::kUniform &&
+        return address_space == builtin::AddressSpace::kUniform &&
                ty->IsAnyOf<type::Array, sem::Struct>();
     };
 
     auto is_uniform_struct = [address_space](const type::Type* ty) {
-        return address_space == type::AddressSpace::kUniform && ty->Is<sem::Struct>();
+        return address_space == builtin::AddressSpace::kUniform && ty->Is<sem::Struct>();
     };
 
     auto required_alignment_of = [&](const type::Type* ty) {
@@ -440,7 +436,7 @@
         return true;
     }
 
-    if (!type::IsHostShareable(address_space)) {
+    if (!builtin::IsHostShareable(address_space)) {
         return true;
     }
 
@@ -453,7 +449,7 @@
     // Among three host-shareable address spaces, f16 is supported in "uniform" and
     // "storage" address space, but not "push_constant" address space yet.
     if (Is<type::F16>(type::Type::DeepestElementOf(store_ty)) &&
-        address_space == type::AddressSpace::kPushConstant) {
+        address_space == builtin::AddressSpace::kPushConstant) {
         AddError("using f16 types in 'push_constant' address space is not implemented yet", source);
         return false;
     }
@@ -530,7 +526,7 @@
             return false;
         }
 
-        if (address_space == type::AddressSpace::kUniform) {
+        if (address_space == builtin::AddressSpace::kUniform) {
             // We already validated that this array member is itself aligned to 16 bytes above, so
             // we only need to validate that stride is a multiple of 16 bytes.
             if (arr->Stride() % 16 != 0) {
@@ -550,9 +546,10 @@
                         "attribute.";
                 }
                 AddError(
-                    "uniform storage requires that array elements be aligned to 16 "
-                    "bytes, but array element alignment is currently " +
-                        std::to_string(arr->Stride()) + ". " + hint,
+                    "uniform storage requires that array elements are aligned to 16 bytes, but "
+                    "array element of type '" +
+                        arr->ElemType()->FriendlyName(symbols_) + "' has a stride of " +
+                        std::to_string(arr->Stride()) + " bytes. " + hint,
                     source);
                 return false;
             }
@@ -596,7 +593,7 @@
     const sem::GlobalVariable* global,
     const utils::Hashmap<OverrideId, const sem::Variable*, 8>& override_ids) const {
     auto* decl = global->Declaration();
-    if (global->AddressSpace() != type::AddressSpace::kWorkgroup &&
+    if (global->AddressSpace() != builtin::AddressSpace::kWorkgroup &&
         IsArrayWithOverrideCount(global->Type())) {
         RaiseArrayWithOverrideCountError(decl->type ? decl->type->source
                                                     : decl->initializer->source);
@@ -604,7 +601,7 @@
     }
     bool ok = Switch(
         decl,  //
-        [&](const ast::Var*) {
+        [&](const ast::Var* var) {
             if (auto* init = global->Initializer();
                 init && init->Stage() > sem::EvaluationStage::kOverride) {
                 AddError("module-scope 'var' initializer must be a constant or override-expression",
@@ -612,8 +609,11 @@
                 return false;
             }
 
-            if (global->AddressSpace() == type::AddressSpace::kNone) {
-                AddError("module-scope 'var' declaration must have a address space", decl->source);
+            if (!var->declared_address_space && !global->Type()->UnwrapRef()->is_handle()) {
+                AddError(
+                    "module-scope 'var' declarations that are not of texture or sampler types must "
+                    "provide an address space",
+                    decl->source);
                 return false;
             }
 
@@ -621,8 +621,8 @@
                 bool is_shader_io_attribute =
                     attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
                                   ast::InvariantAttribute, ast::LocationAttribute>();
-                bool has_io_address_space = global->AddressSpace() == type::AddressSpace::kIn ||
-                                            global->AddressSpace() == type::AddressSpace::kOut;
+                bool has_io_address_space = global->AddressSpace() == builtin::AddressSpace::kIn ||
+                                            global->AddressSpace() == builtin::AddressSpace::kOut;
                 if (!attr->IsAnyOf<ast::BindingAttribute, ast::GroupAttribute,
                                    ast::InternalAttribute>() &&
                     (!is_shader_io_attribute || !has_io_address_space)) {
@@ -654,15 +654,15 @@
         return false;
     }
 
-    if (global->AddressSpace() == type::AddressSpace::kFunction) {
+    if (global->AddressSpace() == builtin::AddressSpace::kFunction) {
         AddError("module-scope 'var' must not use address space 'function'", decl->source);
         return false;
     }
 
     switch (global->AddressSpace()) {
-        case type::AddressSpace::kUniform:
-        case type::AddressSpace::kStorage:
-        case type::AddressSpace::kHandle: {
+        case builtin::AddressSpace::kUniform:
+        case builtin::AddressSpace::kStorage:
+        case builtin::AddressSpace::kHandle: {
             // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
             // Each resource variable must be declared with both group and binding attributes.
             if (!decl->HasBindingPoint()) {
@@ -696,25 +696,23 @@
         return false;
     }
 
-    if (store_ty->is_handle()) {
-        if (var->declared_address_space != type::AddressSpace::kNone) {
-            // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
-            // If the store type is a texture type or a sampler type, then the variable declaration
-            // must not have a address space attribute. The address space will always be handle.
-            AddError("variables of type '" + sem_.TypeNameOf(store_ty) +
-                         "' must not have a address space",
-                     var->source);
-            return false;
-        }
+    if (store_ty->is_handle() && var->declared_address_space) {
+        // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
+        // If the store type is a texture type or a sampler type, then the variable declaration must
+        // not have a address space attribute. The address space will always be handle.
+        AddError("variables of type '" + sem_.TypeNameOf(store_ty) +
+                     "' must not specifiy an address space",
+                 var->source);
+        return false;
     }
 
-    if (var->declared_access != type::Access::kUndefined) {
+    if (var->declared_access) {
         // https://www.w3.org/TR/WGSL/#access-mode-defaults
         // When writing a variable declaration or a pointer type in WGSL source:
         // * For the storage address space, the access mode is optional, and defaults to read.
         // * For other address spaces, the access mode must not be written.
-        if (var->declared_address_space != type::AddressSpace::kStorage) {
-            AddError("only variables in <storage> address space may declare an access mode",
+        if (v->AddressSpace() != builtin::AddressSpace::kStorage) {
+            AddError("only variables in <storage> address space may specify an access mode",
                      var->source);
             return false;
         }
@@ -726,8 +724,8 @@
     }
 
     if (IsValidationEnabled(var->attributes, ast::DisabledValidation::kIgnoreAddressSpace) &&
-        (var->declared_address_space == type::AddressSpace::kIn ||
-         var->declared_address_space == type::AddressSpace::kOut)) {
+        (v->AddressSpace() == builtin::AddressSpace::kIn ||
+         v->AddressSpace() == builtin::AddressSpace::kOut)) {
         AddError("invalid use of input/output address space", var->source);
         return false;
     }
@@ -821,13 +819,13 @@
 
             auto sc = ref->AddressSpace();
             switch (sc) {
-                case type::AddressSpace::kFunction:
-                case type::AddressSpace::kPrivate:
+                case builtin::AddressSpace::kFunction:
+                case builtin::AddressSpace::kPrivate:
                     ok = true;
                     break;
-                case type::AddressSpace::kStorage:
-                case type::AddressSpace::kUniform:
-                case type::AddressSpace::kWorkgroup:
+                case builtin::AddressSpace::kStorage:
+                case builtin::AddressSpace::kUniform:
+                case builtin::AddressSpace::kWorkgroup:
                     ok = enabled_extensions_.Contains(
                         builtin::Extension::kChromiumExperimentalFullPtrParameters);
                     break;
@@ -867,7 +865,8 @@
     stage_name << stage;
     bool is_stage_mismatch = false;
     bool is_output = !is_input;
-    switch (attr->builtin) {
+    auto builtin = sem_.Get(attr)->Value();
+    switch (builtin) {
         case builtin::BuiltinValue::kPosition:
             if (stage != ast::PipelineStage::kNone &&
                 !((is_input && stage == ast::PipelineStage::kFragment) ||
@@ -875,8 +874,9 @@
                 is_stage_mismatch = true;
             }
             if (!(type->is_float_vector() && type->As<type::Vector>()->Width() == 4)) {
-                AddError("store type of " + attr_to_str(attr) + " must be 'vec4<f32>'",
-                         attr->source);
+                std::stringstream err;
+                err << "store type of @builtin(" << builtin << ") must be 'vec4<f32>'";
+                AddError(err.str(), attr->source);
                 return false;
             }
             break;
@@ -889,8 +889,9 @@
                 is_stage_mismatch = true;
             }
             if (!(type->is_unsigned_integer_vector() && type->As<type::Vector>()->Width() == 3)) {
-                AddError("store type of " + attr_to_str(attr) + " must be 'vec3<u32>'",
-                         attr->source);
+                std::stringstream err;
+                err << "store type of @builtin(" << builtin << ") must be 'vec3<u32>'";
+                AddError(err.str(), attr->source);
                 return false;
             }
             break;
@@ -900,7 +901,9 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<type::F32>()) {
-                AddError("store type of " + attr_to_str(attr) + " must be 'f32'", attr->source);
+                std::stringstream err;
+                err << "store type of @builtin(" << builtin << ") must be 'f32'";
+                AddError(err.str(), attr->source);
                 return false;
             }
             break;
@@ -910,7 +913,9 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<type::Bool>()) {
-                AddError("store type of " + attr_to_str(attr) + " must be 'bool'", attr->source);
+                std::stringstream err;
+                err << "store type of @builtin(" << builtin << ") must be 'bool'";
+                AddError(err.str(), attr->source);
                 return false;
             }
             break;
@@ -920,7 +925,9 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<type::U32>()) {
-                AddError("store type of " + attr_to_str(attr) + " must be 'u32'", attr->source);
+                std::stringstream err;
+                err << "store type of @builtin(" << builtin << ") must be 'u32'";
+                AddError(err.str(), attr->source);
                 return false;
             }
             break;
@@ -931,7 +938,9 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<type::U32>()) {
-                AddError("store type of " + attr_to_str(attr) + " must be 'u32'", attr->source);
+                std::stringstream err;
+                err << "store type of @builtin(" << builtin << ") must be 'u32'";
+                AddError(err.str(), attr->source);
                 return false;
             }
             break;
@@ -940,7 +949,9 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<type::U32>()) {
-                AddError("store type of " + attr_to_str(attr) + " must be 'u32'", attr->source);
+                std::stringstream err;
+                err << "store type of @builtin(" << builtin << ") must be 'u32'";
+                AddError(err.str(), attr->source);
                 return false;
             }
             break;
@@ -950,7 +961,9 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<type::U32>()) {
-                AddError("store type of " + attr_to_str(attr) + " must be 'u32'", attr->source);
+                std::stringstream err;
+                err << "store type of @builtin(" << builtin << ") must be 'u32'";
+                AddError(err.str(), attr->source);
                 return false;
             }
             break;
@@ -959,9 +972,10 @@
     }
 
     if (is_stage_mismatch) {
-        AddError(attr_to_str(attr) + " cannot be used in " +
-                     (is_input ? "input of " : "output of ") + stage_name.str() + " pipeline stage",
-                 attr->source);
+        std::stringstream err;
+        err << "@builtin(" << builtin << ") cannot be used in "
+            << (is_input ? "input of " : "output of ") << stage_name.str() << " pipeline stage";
+        AddError(err.str(), attr->source);
         return false;
     }
 
@@ -972,14 +986,19 @@
                                      const type::Type* storage_ty) const {
     auto* type = storage_ty->UnwrapRef();
 
-    if (type->is_integer_scalar_or_vector() && attr->type != ast::InterpolationType::kFlat) {
+    auto i_type = sem_.AsInterpolationType(sem_.Get(attr->type));
+    if (TINT_UNLIKELY(!i_type)) {
+        return false;
+    }
+
+    if (type->is_integer_scalar_or_vector() &&
+        i_type->Value() != builtin::InterpolationType::kFlat) {
         AddError("interpolation type must be 'flat' for integral user-defined IO types",
                  attr->source);
         return false;
     }
 
-    if (attr->type == ast::InterpolationType::kFlat &&
-        attr->sampling != ast::InterpolationSampling::kUndefined) {
+    if (attr->sampling && i_type->Value() == builtin::InterpolationType::kFlat) {
         AddError("flat interpolation attribute must not have a sampling parameter", attr->source);
         return false;
     }
@@ -991,15 +1010,32 @@
     auto* decl = func->Declaration();
 
     for (auto* attr : decl->attributes) {
-        if (attr->Is<ast::WorkgroupAttribute>()) {
-            if (decl->PipelineStage() != ast::PipelineStage::kCompute) {
-                AddError("the workgroup_size attribute is only valid for compute stages",
-                         attr->source);
-                return false;
-            }
-        } else if (!attr->IsAnyOf<ast::DiagnosticAttribute, ast::StageAttribute,
-                                  ast::InternalAttribute>()) {
-            AddError("attribute is not valid for functions", attr->source);
+        bool ok = Switch(
+            attr,  //
+            [&](const ast::WorkgroupAttribute*) {
+                if (decl->PipelineStage() != ast::PipelineStage::kCompute) {
+                    AddError("@workgroup_size is only valid for compute stages", attr->source);
+                    return false;
+                }
+                return true;
+            },
+            [&](const ast::MustUseAttribute*) {
+                if (func->ReturnType()->Is<type::Void>()) {
+                    AddError("@must_use can only be applied to functions that return a value",
+                             attr->source);
+                    return false;
+                }
+                return true;
+            },
+            [&](Default) {
+                if (!attr->IsAnyOf<ast::DiagnosticAttribute, ast::StageAttribute,
+                                   ast::InternalAttribute>()) {
+                    AddError("attribute is not valid for functions", attr->source);
+                    return false;
+                }
+                return true;
+            });
+        if (!ok) {
             return false;
         }
     }
@@ -1097,32 +1133,34 @@
         for (auto* attr : attrs) {
             auto is_invalid_compute_shader_attribute = false;
 
-            if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
+            if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
+                auto builtin = sem_.Get(builtin_attr)->Value();
+
                 if (pipeline_io_attribute) {
                     AddError("multiple entry point IO attributes", attr->source);
-                    AddNote("previously consumed " + attr_to_str(pipeline_io_attribute, location),
+                    AddNote("previously consumed " + AttrToStr(pipeline_io_attribute),
                             pipeline_io_attribute->source);
                     return false;
                 }
                 pipeline_io_attribute = attr;
 
-                if (builtins.Contains(builtin->builtin)) {
-                    AddError(attr_to_str(builtin) +
-                                 " attribute appears multiple times as pipeline " +
-                                 (param_or_ret == ParamOrRetType::kParameter ? "input" : "output"),
-                             decl->source);
+                if (builtins.Contains(builtin)) {
+                    std::stringstream err;
+                    err << "@builtin(" << builtin << ") appears multiple times as pipeline "
+                        << (param_or_ret == ParamOrRetType::kParameter ? "input" : "output");
+                    AddError(err.str(), decl->source);
                     return false;
                 }
 
-                if (!BuiltinAttribute(builtin, ty, stage,
+                if (!BuiltinAttribute(builtin_attr, ty, stage,
                                       /* is_input */ param_or_ret == ParamOrRetType::kParameter)) {
                     return false;
                 }
-                builtins.Add(builtin->builtin);
+                builtins.Add(builtin);
             } else if (auto* loc_attr = attr->As<ast::LocationAttribute>()) {
                 if (pipeline_io_attribute) {
                     AddError("multiple entry point IO attributes", attr->source);
-                    AddNote("previously consumed " + attr_to_str(pipeline_io_attribute),
+                    AddNote("previously consumed " + AttrToStr(pipeline_io_attribute),
                             pipeline_io_attribute->source);
                     return false;
                 }
@@ -1182,16 +1220,16 @@
                     if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
                         param_or_ret == ParamOrRetType::kReturnType) {
                         AddError(
-                            "integral user-defined vertex outputs must have a flat "
-                            "interpolation attribute",
+                            "integral user-defined vertex outputs must have a flat interpolation "
+                            "attribute",
                             source);
                         return false;
                     }
                     if (decl->PipelineStage() == ast::PipelineStage::kFragment &&
                         param_or_ret == ParamOrRetType::kParameter) {
                         AddError(
-                            "integral user-defined fragment inputs must have a flat "
-                            "interpolation attribute",
+                            "integral user-defined fragment inputs must have a flat interpolation "
+                            "attribute",
                             source);
                         return false;
                     }
@@ -1210,15 +1248,14 @@
             if (invariant_attribute) {
                 bool has_position = false;
                 if (pipeline_io_attribute) {
-                    if (auto* builtin = pipeline_io_attribute->As<ast::BuiltinAttribute>()) {
-                        has_position = (builtin->builtin == builtin::BuiltinValue::kPosition);
+                    if (auto* builtin_attr = pipeline_io_attribute->As<ast::BuiltinAttribute>()) {
+                        auto builtin = sem_.Get(builtin_attr)->Value();
+                        has_position = (builtin == builtin::BuiltinValue::kPosition);
                     }
                 }
                 if (!has_position) {
-                    AddError(
-                        "invariant attribute must only be applied to a position "
-                        "builtin",
-                        invariant_attribute->source);
+                    AddError("invariant attribute must only be applied to a position builtin",
+                             invariant_attribute->source);
                     return false;
                 }
             }
@@ -1279,9 +1316,10 @@
         // Check module-scope variables, as the SPIR-V sanitizer generates these.
         bool found = false;
         for (auto* global : func->TransitivelyReferencedGlobals()) {
-            if (auto* builtin =
+            if (auto* builtin_attr =
                     ast::GetAttribute<ast::BuiltinAttribute>(global->Declaration()->attributes)) {
-                if (builtin->builtin == builtin::BuiltinValue::kPosition) {
+                auto builtin = sem_.Get(builtin_attr)->Value();
+                if (builtin == builtin::BuiltinValue::kPosition) {
                     found = true;
                     break;
                 }
@@ -1374,8 +1412,8 @@
 bool Validator::Statements(utils::VectorRef<const ast::Statement*> stmts) const {
     for (auto* stmt : stmts) {
         if (!sem_.Get(stmt)->IsReachable()) {
-            if (!AddDiagnostic(ast::DiagnosticRule::kChromiumUnreachableCode, "code is unreachable",
-                               stmt->source)) {
+            if (!AddDiagnostic(builtin::DiagnosticRule::kChromiumUnreachableCode,
+                               "code is unreachable", stmt->source)) {
                 return false;
             }
             break;
@@ -1447,22 +1485,39 @@
 }
 
 bool Validator::Call(const sem::Call* call, sem::Statement* current_statement) const {
+    if (!call->Target()->MustUse()) {
+        return true;
+    }
+
     auto* expr = call->Declaration();
     bool is_call_stmt =
         current_statement && Is<ast::CallStatement>(current_statement->Declaration(),
                                                     [&](auto* stmt) { return stmt->expr == expr; });
     if (is_call_stmt) {
-        return Switch(
+        // Call target is annotated with @must_use, but was used as a call statement.
+        Switch(
             call->Target(),  //
-            [&](const sem::TypeConversion*) {
-                AddError("type conversion evaluated but not used", call->Declaration()->source);
-                return false;
+            [&](const sem::Function* fn) {
+                AddError("ignoring return value of function '" +
+                             symbols_.NameFor(fn->Declaration()->name->symbol) +
+                             "' annotated with @must_use",
+                         call->Declaration()->source);
+                sem_.NoteDeclarationSource(fn->Declaration());
             },
-            [&](const sem::TypeInitializer*) {
-                AddError("type initializer evaluated but not used", call->Declaration()->source);
-                return false;
+            [&](const sem::Builtin* b) {
+                AddError("ignoring return value of builtin '" + utils::ToString(b->Type()) + "'",
+                         call->Declaration()->source);
             },
-            [&](Default) { return true; });
+            [&](const sem::ValueConversion*) {
+                AddError("value conversion evaluated but not used", call->Declaration()->source);
+            },
+            [&](const sem::ValueConstructor*) {
+                AddError("value constructor evaluated but not used", call->Declaration()->source);
+            },
+            [&](Default) {
+                AddError("return value of call not used", call->Declaration()->source);
+            });
+        return false;
     }
 
     return true;
@@ -1771,14 +1826,14 @@
 bool Validator::StructureInitializer(const ast::CallExpression* ctor,
                                      const sem::Struct* struct_type) const {
     if (!struct_type->IsConstructible()) {
-        AddError("struct initializer has non-constructible type", ctor->source);
+        AddError("structure constructor has non-constructible type", ctor->source);
         return false;
     }
 
     if (ctor->args.Length() > 0) {
         if (ctor->args.Length() != struct_type->Members().Length()) {
             std::string fm = ctor->args.Length() < struct_type->Members().Length() ? "few" : "many";
-            AddError("struct initializer has too " + fm + " inputs: expected " +
+            AddError("structure constructor has too " + fm + " inputs: expected " +
                          std::to_string(struct_type->Members().Length()) + ", found " +
                          std::to_string(ctor->args.Length()),
                      ctor->source);
@@ -1789,7 +1844,7 @@
             auto* value_ty = sem_.TypeOf(value);
             if (member->Type() != value_ty->UnwrapRef()) {
                 AddError(
-                    "type in struct initializer does not match struct member type: expected '" +
+                    "type in structure constructor does not match struct member type: expected '" +
                         sem_.TypeNameOf(member->Type()) + "', found '" + sem_.TypeNameOf(value_ty) +
                         "'",
                     value->source);
@@ -1800,7 +1855,7 @@
     return true;
 }
 
-bool Validator::ArrayInitializer(const ast::CallExpression* ctor,
+bool Validator::ArrayConstructor(const ast::CallExpression* ctor,
                                  const type::Array* array_type) const {
     auto& values = ctor->args;
     auto* elem_ty = array_type->ElemType();
@@ -1827,7 +1882,7 @@
     }
 
     if (!elem_ty->IsConstructible()) {
-        AddError("array initializer has non-constructible element type", ctor->source);
+        AddError("array constructor has non-constructible element type", ctor->source);
         return false;
     }
 
@@ -1839,7 +1894,7 @@
     const auto count = c->As<type::ConstantArrayCount>()->value;
     if (!values.IsEmpty() && (values.Length() != count)) {
         std::string fm = values.Length() < count ? "few" : "many";
-        AddError("array initializer has too " + fm + " elements: expected " +
+        AddError("array constructor has too " + fm + " elements: expected " +
                      std::to_string(count) + ", found " + std::to_string(values.Length()),
                  ctor->source);
         return false;
@@ -1882,7 +1937,7 @@
         auto stage = entry_point->Declaration()->PipelineStage();
         if (stage != ast::PipelineStage::kCompute) {
             for (auto* var : func->DirectlyReferencedGlobals()) {
-                if (var->AddressSpace() == type::AddressSpace::kWorkgroup) {
+                if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
                     std::stringstream stage_name;
                     stage_name << stage;
                     for (auto* user : var->Users()) {
@@ -1968,7 +2023,7 @@
 
         auto check_push_constant = [&](const sem::Function* func, const sem::Function* ep) {
             for (auto* var : func->DirectlyReferencedGlobals()) {
-                if (var->AddressSpace() != type::AddressSpace::kPushConstant ||
+                if (var->AddressSpace() != builtin::AddressSpace::kPushConstant ||
                     var == push_constant_var) {
                     continue;
                 }
@@ -2119,12 +2174,13 @@
                     }
                     return true;
                 },
-                [&](const ast::BuiltinAttribute* builtin) {
-                    if (!BuiltinAttribute(builtin, member->Type(), stage,
+                [&](const ast::BuiltinAttribute* builtin_attr) {
+                    if (!BuiltinAttribute(builtin_attr, member->Type(), stage,
                                           /* is_input */ false)) {
                         return false;
                     }
-                    if (builtin->builtin == builtin::BuiltinValue::kPosition) {
+                    auto builtin = sem_.Get(builtin_attr)->Value();
+                    if (builtin == builtin::BuiltinValue::kPosition) {
                         has_position = true;
                     }
                     return true;
@@ -2207,18 +2263,18 @@
 
     if (!type->is_numeric_scalar_or_vector()) {
         std::string invalid_type = sem_.TypeNameOf(type);
-        AddError("cannot apply 'location' attribute to declaration of type '" + invalid_type + "'",
-                 source);
+        AddError("cannot apply @location to declaration of type '" + invalid_type + "'", source);
         AddNote(
-            "'location' attribute must only be applied to declarations of numeric scalar or "
-            "numeric vector type",
+            "@location must only be applied to declarations of numeric scalar or numeric vector "
+            "type",
             loc_attr->source);
         return false;
     }
 
     if (!locations.Add(location)) {
-        AddError(attr_to_str(loc_attr, location) + " attribute appears multiple times",
-                 loc_attr->source);
+        std::stringstream err;
+        err << "@location(" << location << ") appears multiple times";
+        AddError(err.str(), loc_attr->source);
         return false;
     }
 
@@ -2335,26 +2391,47 @@
     }
 
     // https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
-    auto const* lhs_ty = sem_.TypeOf(lhs);
-
-    if (auto* var_user = sem_.Get<sem::VariableUser>(lhs)) {
-        auto* v = var_user->Variable()->Declaration();
-        const char* err = Switch(
-            v,  //
-            [&](const ast::Parameter*) { return "cannot assign to function parameter"; },
-            [&](const ast::Let*) { return "cannot assign to 'let'"; },
-            [&](const ast::Override*) { return "cannot assign to 'override'"; });
-        if (err) {
-            AddError(err, lhs->source);
-            AddNote("'" + symbols_.NameFor(v->name->symbol) + "' is declared here:", v->source);
-            return false;
-        }
-    }
+    auto const* lhs_sem = sem_.GetVal(lhs);
+    auto const* lhs_ty = lhs_sem->Type();
 
     auto* lhs_ref = lhs_ty->As<type::Reference>();
     if (!lhs_ref) {
         // LHS is not a reference, so it has no storage.
-        AddError("cannot assign to value of type '" + sem_.TypeNameOf(lhs_ty) + "'", lhs->source);
+        AddError("cannot assign to " + sem_.Describe(lhs_sem), lhs->source);
+
+        auto* expr = lhs;
+        while (expr) {
+            expr = Switch(
+                expr,  //
+                [&](const ast::AccessorExpression* e) { return e->object; },
+                [&](const ast::IdentifierExpression* i) {
+                    if (auto user = sem_.Get<sem::VariableUser>(i)) {
+                        Switch(
+                            user->Variable()->Declaration(),  //
+                            [&](const ast::Let* v) {
+                                AddNote("'let' variables are immutable",
+                                        user->Declaration()->source);
+                                sem_.NoteDeclarationSource(v);
+                            },
+                            [&](const ast::Const* v) {
+                                AddNote("'const' variables are immutable",
+                                        user->Declaration()->source);
+                                sem_.NoteDeclarationSource(v);
+                            },
+                            [&](const ast::Override* v) {
+                                AddNote("'override' variables are immutable",
+                                        user->Declaration()->source);
+                                sem_.NoteDeclarationSource(v);
+                            },
+                            [&](const ast::Parameter* v) {
+                                AddNote("parameters are immutable", user->Declaration()->source);
+                                sem_.NoteDeclarationSource(v);
+                            });
+                    }
+                    return nullptr;
+                });
+        }
+
         return false;
     }
 
@@ -2372,7 +2449,7 @@
         AddError("storage type of assignment must be constructible", a->source);
         return false;
     }
-    if (lhs_ref->Access() == type::Access::kRead) {
+    if (lhs_ref->Access() == builtin::Access::kRead) {
         AddError("cannot store into a read-only type '" + sem_.RawTypeNameOf(lhs_ty) + "'",
                  a->source);
         return false;
@@ -2413,7 +2490,7 @@
         return false;
     }
 
-    if (lhs_ref->Access() == type::Access::kRead) {
+    if (lhs_ref->Access() == builtin::Access::kRead) {
         AddError("cannot modify read-only type '" + sem_.RawTypeNameOf(lhs_ty) + "'", inc->source);
         return false;
     }
@@ -2504,15 +2581,15 @@
 
 bool Validator::CheckTypeAccessAddressSpace(
     const type::Type* store_ty,
-    type::Access access,
-    type::AddressSpace address_space,
+    builtin::Access access,
+    builtin::AddressSpace address_space,
     utils::VectorRef<const tint::ast::Attribute*> attributes,
     const Source& source) const {
     if (!AddressSpaceLayout(store_ty, address_space, source)) {
         return false;
     }
 
-    if (address_space == type::AddressSpace::kPushConstant &&
+    if (address_space == builtin::AddressSpace::kPushConstant &&
         !enabled_extensions_.Contains(builtin::Extension::kChromiumExperimentalPushConstant) &&
         IsValidationEnabled(attributes, ast::DisabledValidation::kIgnoreAddressSpace)) {
         AddError(
@@ -2522,19 +2599,19 @@
         return false;
     }
 
-    if (address_space == type::AddressSpace::kStorage && access == type::Access::kWrite) {
-        // The access mode for the storage address space can only be 'read' or
-        // 'read_write'.
+    if (address_space == builtin::AddressSpace::kStorage && access == builtin::Access::kWrite) {
+        // The access mode for the storage address space can only be 'read' or 'read_write'.
         AddError("access mode 'write' is not valid for the 'storage' address space", source);
         return false;
     }
 
     auto atomic_error = [&]() -> const char* {
-        if (address_space != type::AddressSpace::kStorage &&
-            address_space != type::AddressSpace::kWorkgroup) {
+        if (address_space != builtin::AddressSpace::kStorage &&
+            address_space != builtin::AddressSpace::kWorkgroup) {
             return "atomic variables must have <storage> or <workgroup> address space";
         }
-        if (address_space == type::AddressSpace::kStorage && access != type::Access::kReadWrite) {
+        if (address_space == builtin::AddressSpace::kStorage &&
+            access != builtin::Access::kReadWrite) {
             return "atomic variables in <storage> address space must have read_write access "
                    "mode";
         }
diff --git a/src/tint/resolver/validator.h b/src/tint/resolver/validator.h
index 499dcda..45c98c8 100644
--- a/src/tint/resolver/validator.h
+++ b/src/tint/resolver/validator.h
@@ -61,7 +61,6 @@
 class Materialize;
 class Statement;
 class SwitchStatement;
-class TypeInitializer;
 class WhileStatement;
 }  // namespace tint::sem
 namespace tint::type {
@@ -75,7 +74,7 @@
     /// The type
     const type::Type* type;
     /// The address space
-    type::AddressSpace address_space;
+    builtin::AddressSpace address_space;
 
     /// Equality operator
     /// @param other the other TypeAndAddressSpace to compare this TypeAndAddressSpace to
@@ -86,7 +85,7 @@
 };
 
 /// DiagnosticFilterStack is a scoped stack of diagnostic filters.
-using DiagnosticFilterStack = ScopeStack<ast::DiagnosticRule, ast::DiagnosticSeverity>;
+using DiagnosticFilterStack = ScopeStack<builtin::DiagnosticRule, builtin::DiagnosticSeverity>;
 
 /// Validation logic for various ast nodes. The validations in general should
 /// be shallow and depend on the resolver to call on children. The validations
@@ -127,7 +126,7 @@
     /// @param msg the diagnostic message
     /// @param source the diagnostic source
     /// @returns false if the diagnostic is an error for the given trigger rule
-    bool AddDiagnostic(ast::DiagnosticRule rule,
+    bool AddDiagnostic(builtin::DiagnosticRule rule,
                        const std::string& msg,
                        const Source& source) const;
 
@@ -435,7 +434,7 @@
     /// @param initializer the RHS initializer expression
     /// @returns true on succes, false otherwise
     bool VariableInitializer(const ast::Variable* v,
-                             type::AddressSpace address_space,
+                             builtin::AddressSpace address_space,
                              const type::Type* storage_type,
                              const sem::ValueExpression* initializer) const;
 
@@ -445,11 +444,11 @@
     /// @returns true on success, false otherwise
     bool Vector(const type::Type* el_ty, const Source& source) const;
 
-    /// Validates an array initializer
+    /// Validates an array constructor
     /// @param ctor the call expresion to validate
     /// @param arr_type the type of the array
     /// @returns true on success, false otherwise
-    bool ArrayInitializer(const ast::CallExpression* ctor, const type::Array* arr_type) const;
+    bool ArrayConstructor(const ast::CallExpression* ctor, const type::Array* arr_type) const;
 
     /// Validates a texture builtin function
     /// @param call the builtin call to validate
@@ -488,7 +487,7 @@
     /// @param sc the address space
     /// @param source the source of the type
     /// @returns true on success, false otherwise
-    bool AddressSpaceLayout(const type::Type* type, type::AddressSpace sc, Source source) const;
+    bool AddressSpaceLayout(const type::Type* type, builtin::AddressSpace sc, Source source) const;
 
     /// @returns true if the attribute list contains a
     /// ast::DisableValidationAttribute with the validation mode equal to
@@ -542,8 +541,8 @@
     /// @param source the source for the error
     /// @returns true on success, false if an error was raised.
     bool CheckTypeAccessAddressSpace(const type::Type* store_ty,
-                                     type::Access access,
-                                     type::AddressSpace address_space,
+                                     builtin::Access access,
+                                     builtin::AddressSpace address_space,
                                      utils::VectorRef<const tint::ast::Attribute*> attributes,
                                      const Source& source) const;
     SymbolTable& symbols_;
diff --git a/src/tint/resolver/validator_is_storeable_test.cc b/src/tint/resolver/validator_is_storeable_test.cc
index 6c1fce4..d01d21c 100644
--- a/src/tint/resolver/validator_is_storeable_test.cc
+++ b/src/tint/resolver/validator_is_storeable_test.cc
@@ -78,8 +78,8 @@
 }
 
 TEST_F(ValidatorIsStorableTest, Pointer) {
-    auto* ptr = create<type::Pointer>(create<type::I32>(), type::AddressSpace::kPrivate,
-                                      type::Access::kReadWrite);
+    auto* ptr = create<type::Pointer>(create<type::I32>(), builtin::AddressSpace::kPrivate,
+                                      builtin::Access::kReadWrite);
     EXPECT_FALSE(v()->IsStorable(ptr));
 }
 
diff --git a/src/tint/resolver/type_initializer_validation_test.cc b/src/tint/resolver/value_constructor_validation_test.cc
similarity index 80%
rename from src/tint/resolver/type_initializer_validation_test.cc
rename to src/tint/resolver/value_constructor_validation_test.cc
index dde1a2e..8ab1cab 100644
--- a/src/tint/resolver/type_initializer_validation_test.cc
+++ b/src/tint/resolver/value_constructor_validation_test.cc
@@ -14,8 +14,8 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/type/reference.h"
 
 using namespace tint::number_suffixes;  // NOLINT
@@ -42,7 +42,7 @@
 using builder::vec3;
 using builder::vec4;
 
-class ResolverTypeInitializerValidationTest : public resolver::TestHelper, public testing::Test {};
+class ResolverValueConstructorValidationTest : public resolver::TestHelper, public testing::Test {};
 
 namespace InferTypeTest {
 struct Params {
@@ -56,7 +56,7 @@
     return Params{DataType<T>::AST, DataType<T>::ExprFromDouble, DataType<T>::Sem};
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferTypeTest_Simple) {
+TEST_F(ResolverValueConstructorValidationTest, InferTypeTest_Simple) {
     // var a = 1i;
     // var b = a;
     auto* a = Var("a", Expr(1_i));
@@ -70,15 +70,15 @@
     ASSERT_TRUE(TypeOf(a_ident)->Is<type::Reference>());
     EXPECT_TRUE(TypeOf(a_ident)->As<type::Reference>()->StoreType()->Is<type::I32>());
     EXPECT_EQ(TypeOf(a_ident)->As<type::Reference>()->AddressSpace(),
-              type::AddressSpace::kFunction);
+              builtin::AddressSpace::kFunction);
     ASSERT_TRUE(TypeOf(b_ident)->Is<type::Reference>());
     EXPECT_TRUE(TypeOf(b_ident)->As<type::Reference>()->StoreType()->Is<type::I32>());
     EXPECT_EQ(TypeOf(b_ident)->As<type::Reference>()->AddressSpace(),
-              type::AddressSpace::kFunction);
+              builtin::AddressSpace::kFunction);
 }
 
-using InferTypeTest_FromInitializerExpression = ResolverTestWithParam<Params>;
-TEST_P(InferTypeTest_FromInitializerExpression, All) {
+using InferTypeTest_FromConstructorExpression = ResolverTestWithParam<Params>;
+TEST_P(InferTypeTest_FromConstructorExpression, All) {
     // e.g. for vec3<f32>
     // {
     //   var a = vec3<f32>(0.0, 0.0, 0.0)
@@ -97,13 +97,14 @@
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
     auto* got = TypeOf(a_ident);
-    auto* expected = create<type::Reference>(
-        params.create_rhs_sem_type(*this), type::AddressSpace::kFunction, type::Access::kReadWrite);
+    auto* expected =
+        create<type::Reference>(params.create_rhs_sem_type(*this), builtin::AddressSpace::kFunction,
+                                builtin::Access::kReadWrite);
     ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
                              << "expected: " << FriendlyName(expected) << "\n";
 }
 
-static constexpr Params from_initializer_expression_cases[] = {
+static constexpr Params from_constructor_expression_cases[] = {
     ParamsFor<bool>(),
     ParamsFor<i32>(),
     ParamsFor<u32>(),
@@ -127,9 +128,9 @@
     ParamsFor<alias<mat3x3<f32>>>(),
     ParamsFor<alias<mat3x3<f16>>>(),
 };
-INSTANTIATE_TEST_SUITE_P(ResolverTypeInitializerValidationTest,
-                         InferTypeTest_FromInitializerExpression,
-                         testing::ValuesIn(from_initializer_expression_cases));
+INSTANTIATE_TEST_SUITE_P(ResolverValueConstructorValidationTest,
+                         InferTypeTest_FromConstructorExpression,
+                         testing::ValuesIn(from_constructor_expression_cases));
 
 using InferTypeTest_FromArithmeticExpression = ResolverTestWithParam<Params>;
 TEST_P(InferTypeTest_FromArithmeticExpression, All) {
@@ -151,8 +152,9 @@
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
     auto* got = TypeOf(a_ident);
-    auto* expected = create<type::Reference>(
-        params.create_rhs_sem_type(*this), type::AddressSpace::kFunction, type::Access::kReadWrite);
+    auto* expected =
+        create<type::Reference>(params.create_rhs_sem_type(*this), builtin::AddressSpace::kFunction,
+                                builtin::Access::kReadWrite);
     ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
                              << "expected: " << FriendlyName(expected) << "\n";
 }
@@ -168,7 +170,7 @@
     ParamsFor<alias<vec3<f32>>>(),
     ParamsFor<alias<mat3x3<f32>>>(),
 };
-INSTANTIATE_TEST_SUITE_P(ResolverTypeInitializerValidationTest,
+INSTANTIATE_TEST_SUITE_P(ResolverValueConstructorValidationTest,
                          InferTypeTest_FromArithmeticExpression,
                          testing::ValuesIn(from_arithmetic_expression_cases));
 
@@ -199,8 +201,9 @@
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
     auto* got = TypeOf(a_ident);
-    auto* expected = create<type::Reference>(
-        params.create_rhs_sem_type(*this), type::AddressSpace::kFunction, type::Access::kReadWrite);
+    auto* expected =
+        create<type::Reference>(params.create_rhs_sem_type(*this), builtin::AddressSpace::kFunction,
+                                builtin::Access::kReadWrite);
     ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
                              << "expected: " << FriendlyName(expected) << "\n";
 }
@@ -228,7 +231,7 @@
     ParamsFor<alias<mat3x3<f32>>>(),
     ParamsFor<alias<mat3x3<f16>>>(),
 };
-INSTANTIATE_TEST_SUITE_P(ResolverTypeInitializerValidationTest,
+INSTANTIATE_TEST_SUITE_P(ResolverValueConstructorValidationTest,
                          InferTypeTest_FromCallExpression,
                          testing::ValuesIn(from_call_expression_cases));
 
@@ -339,8 +342,8 @@
     ParamsFor<mat3x2<f32>, mat3x2<f16>>(Kind::Conversion),  //
 };
 
-using ConversionInitializerValidTest = ResolverTestWithParam<Params>;
-TEST_P(ConversionInitializerValidTest, All) {
+using ConversionConstructorValidTest = ResolverTestWithParam<Params>;
+TEST_P(ConversionConstructorValidTest, All) {
     auto& params = GetParam();
 
     Enable(builtin::Extension::kF16);
@@ -371,7 +374,7 @@
     ASSERT_NE(call, nullptr);
     switch (params.kind) {
         case Kind::Construct: {
-            auto* ctor = call->Target()->As<sem::TypeInitializer>();
+            auto* ctor = call->Target()->As<sem::ValueConstructor>();
             ASSERT_NE(ctor, nullptr);
             EXPECT_EQ(call->Type(), ctor->ReturnType());
             ASSERT_EQ(ctor->Parameters().Length(), 1u);
@@ -379,7 +382,7 @@
             break;
         }
         case Kind::Conversion: {
-            auto* conv = call->Target()->As<sem::TypeConversion>();
+            auto* conv = call->Target()->As<sem::ValueConversion>();
             ASSERT_NE(conv, nullptr);
             EXPECT_EQ(call->Type(), conv->ReturnType());
             ASSERT_EQ(conv->Parameters().Length(), 1u);
@@ -388,8 +391,8 @@
         }
     }
 }
-INSTANTIATE_TEST_SUITE_P(ResolverTypeInitializerValidationTest,
-                         ConversionInitializerValidTest,
+INSTANTIATE_TEST_SUITE_P(ResolverValueConstructorValidationTest,
+                         ConversionConstructorValidTest,
                          testing::ValuesIn(valid_cases));
 
 constexpr CreatePtrs all_types[] = {
@@ -417,10 +420,10 @@
     CreatePtrsFor<mat3x2<f16>>(),  //
 };
 
-using ConversionInitializerInvalidTest = ResolverTestWithParam<std::tuple<CreatePtrs,  // lhs
+using ConversionConstructorInvalidTest = ResolverTestWithParam<std::tuple<CreatePtrs,  // lhs
                                                                           CreatePtrs   // rhs
                                                                           >>;
-TEST_P(ConversionInitializerInvalidTest, All) {
+TEST_P(ConversionConstructorInvalidTest, All) {
     auto& params = GetParam();
 
     auto& lhs_params = std::get<0>(params);
@@ -460,33 +463,33 @@
 
     ASSERT_FALSE(r()->Resolve());
 }
-INSTANTIATE_TEST_SUITE_P(ResolverTypeInitializerValidationTest,
-                         ConversionInitializerInvalidTest,
+INSTANTIATE_TEST_SUITE_P(ResolverValueConstructorValidationTest,
+                         ConversionConstructorInvalidTest,
                          testing::Combine(testing::ValuesIn(all_types),
                                           testing::ValuesIn(all_types)));
 
-TEST_F(ResolverTypeInitializerValidationTest, ConversionInitializerInvalid_TooManyInitializers) {
+TEST_F(ResolverValueConstructorValidationTest, ConversionConstructorInvalid_TooManyConstructors) {
     auto* a = Var("a", ty.f32(), Call(Source{{12, 34}}, ty.f32(), Expr(1_f), Expr(2_f)));
     WrapInFunction(a);
 
     ASSERT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for f32(f32, f32)"));
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for f32(f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ConversionInitializerInvalid_InvalidInitializer) {
+TEST_F(ResolverValueConstructorValidationTest, ConversionConstructorInvalid_InvalidConstructor) {
     auto* a = Var("a", ty.f32(), Call(Source{{12, 34}}, ty.f32(), Call(ty.array<f32, 4>())));
     WrapInFunction(a);
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for f32(array<f32, 4>)"));
+                HasSubstr("12:34 error: no matching constructor for f32(array<f32, 4>)"));
 }
 
 }  // namespace ConversionConstructTest
 
-namespace ArrayInitializer {
+namespace ArrayConstructor {
 
-TEST_F(ResolverTypeInitializerValidationTest, Array_ZeroValue_Pass) {
+TEST_F(ResolverValueConstructorValidationTest, Array_ZeroValue_Pass) {
     // array<u32, 10u>();
     auto* tc = array<u32, 10>();
     WrapInFunction(tc);
@@ -496,13 +499,13 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 0u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Array_U32U32U32) {
+TEST_F(ResolverValueConstructorValidationTest, Array_U32U32U32) {
     // array<u32, 3u>(0u, 10u, 20u);
     auto* tc = array<u32, 3>(0_u, 10_u, 20_u);
     WrapInFunction(tc);
@@ -512,7 +515,7 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -521,7 +524,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArray_U32U32U32) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArray_U32U32U32) {
     // array(0u, 10u, 20u);
     auto* tc = array<Infer>(Source{{12, 34}}, 0_u, 10_u, 20_u);
     WrapInFunction(tc);
@@ -531,7 +534,7 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -540,7 +543,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Array_U32AIU32) {
+TEST_F(ResolverValueConstructorValidationTest, Array_U32AIU32) {
     // array<u32, 3u>(0u, 10, 20u);
     auto* tc = array<u32, 3>(0_u, 10_a, 20_u);
     WrapInFunction(tc);
@@ -550,7 +553,7 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -559,7 +562,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArray_U32AIU32) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArray_U32AIU32) {
     // array(0u, 10u, 20u);
     auto* tc = array<Infer>(Source{{12, 34}}, 0_u, 10_a, 20_u);
     WrapInFunction(tc);
@@ -569,7 +572,7 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -578,7 +581,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayU32_AIAIAI) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayU32_AIAIAI) {
     // array<u32, 3u>(0, 10, 20);
     auto* tc = array<u32, 3>(0_a, 10_a, 20_a);
     WrapInFunction(tc);
@@ -588,7 +591,7 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -597,7 +600,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArray_AIAIAI) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArray_AIAIAI) {
     // const c = array(0, 10, 20);
     auto* tc = array<Infer>(Source{{12, 34}}, 0_a, 10_a, 20_a);
     WrapInFunction(Decl(Const("C", tc)));
@@ -607,7 +610,7 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -616,7 +619,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::AbstractInt>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayU32_VecI32_VecAI) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayU32_VecI32_VecAI) {
     // array(vec2(10i), vec2(20));
     auto* tc = array<Infer>(Source{{12, 34}},              //
                             Call(ty.vec<Infer>(2), 20_i),  //
@@ -628,7 +631,7 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -638,7 +641,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->As<type::Vector>()->type()->Is<type::I32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayU32_VecAI_VecF32) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayU32_VecAI_VecF32) {
     // array(vec2(20), vec2(10f));
     auto* tc = array<Infer>(Source{{12, 34}},              //
                             Call(ty.vec<Infer>(2), 20_a),  //
@@ -650,7 +653,7 @@
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
     EXPECT_TRUE(call->Type()->Is<type::Array>());
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -660,7 +663,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->As<type::Vector>()->type()->Is<type::F32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayArgumentTypeMismatch_U32F32) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_U32F32) {
     // array<u32, 3u>(0u, 1.0f, 20u);
     auto* tc = array<u32, 3>(0_u, Expr(Source{{12, 34}}, 1_f), 20_u);
     WrapInFunction(tc);
@@ -669,19 +672,19 @@
     EXPECT_EQ(r()->error(), R"(12:34 error: 'f32' cannot be used to construct an array of 'u32')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayArgumentTypeMismatch_U32F32) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_U32F32) {
     // array(0u, 1.0f, 20u);
     auto* tc = array<Infer>(Source{{12, 34}}, 0_u, 1_f, 20_u);
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'u32'
 note: argument 1 is of type 'f32')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayArgumentTypeMismatch_F32I32) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_F32I32) {
     // array<f32, 1u>(1i);
     auto* tc = array<f32, 1>(Expr(Source{{12, 34}}, 1_i));
     WrapInFunction(tc);
@@ -690,19 +693,19 @@
     EXPECT_EQ(r()->error(), R"(12:34 error: 'i32' cannot be used to construct an array of 'f32')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayArgumentTypeMismatch_F32I32) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_F32I32) {
     // array(1f, 1i);
     auto* tc = array<Infer>(Source{{12, 34}}, 1_f, 1_i);
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'f32'
 note: argument 1 is of type 'i32')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayArgumentTypeMismatch_U32I32) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_U32I32) {
     // array<u32, 1u>(1i, 0u, 0u, 0u, 0u, 0u);
     auto* tc = array<u32, 1>(Expr(Source{{12, 34}}, 1_i), 0_u, 0_u, 0_u, 0_u);
     WrapInFunction(tc);
@@ -711,19 +714,19 @@
     EXPECT_EQ(r()->error(), R"(12:34 error: 'i32' cannot be used to construct an array of 'u32')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayArgumentTypeMismatch_U32I32) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_U32I32) {
     // array(1i, 0u, 0u, 0u, 0u, 0u);
     auto* tc = array<Infer>(Source{{12, 34}}, 1_i, 0_u, 0_u, 0_u, 0_u);
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'i32'
 note: argument 1 is of type 'u32')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayArgumentTypeMismatch_I32Vec2) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_I32Vec2) {
     // array<i32, 3u>(1i, vec2<i32>());
     auto* tc = array<i32, 3>(1_i, vec2<i32>(Source{{12, 34}}));
     WrapInFunction(tc);
@@ -732,18 +735,18 @@
               R"(12:34 error: 'vec2<i32>' cannot be used to construct an array of 'i32')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayArgumentTypeMismatch_I32Vec2) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_I32Vec2) {
     // array(1i, vec2<i32>());
     auto* tc = array<Infer>(Source{{12, 34}}, 1_i, vec2<i32>());
     WrapInFunction(tc);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'i32'
 note: argument 1 is of type 'vec2<i32>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayArgumentTypeMismatch_Vec3i32_Vec3u32) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_Vec3i32_Vec3u32) {
     // array<vec3<i32>, 2u>(vec3<u32>(), vec3<u32>());
     auto* t = array(ty.vec3<i32>(), 2_u, vec3<u32>(Source{{12, 34}}), vec3<u32>());
     WrapInFunction(t);
@@ -753,31 +756,31 @@
               R"(12:34 error: 'vec3<u32>' cannot be used to construct an array of 'vec3<i32>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3u32) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3u32) {
     // array(vec3<i32>(), vec3<u32>());
     auto* t = array<Infer>(Source{{12, 34}}, vec3<i32>(), vec3<u32>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'vec3<i32>'
 note: argument 1 is of type 'vec3<u32>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3AF) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3AF) {
     // array(vec3<i32>(), vec3(1.0));
     auto* t = array<Infer>(Source{{12, 34}}, vec3<i32>(), Call("vec3", 1._a));
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'vec3<i32>'
 note: argument 1 is of type 'vec3<abstract-float>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayArgumentTypeMismatch_Vec3i32_Vec3bool) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_Vec3i32_Vec3bool) {
     // array<vec3<i32>, 2u>(vec3<i32>(), vec3<bool>());
     auto* t = array(ty.vec3<i32>(), 2_u, vec3<i32>(), vec3<bool>());
     WrapInFunction(t);
@@ -787,19 +790,19 @@
               R"(error: 'vec3<bool>' cannot be used to construct an array of 'vec3<i32>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3bool) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3bool) {
     // array(vec3<i32>(), vec3<bool>());
     auto* t = array<Infer>(Source{{12, 34}}, vec3<i32>(), vec3<bool>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'vec3<i32>'
 note: argument 1 is of type 'vec3<bool>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayOfArray_SubElemSizeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayOfArray_SubElemSizeMismatch) {
     // array<array<i32, 2u>, 2u>(array<i32, 3u>(), array<i32, 2u>());
     auto* t = array(Source{{12, 34}}, ty.array<i32, 2>(), 2_i, array<i32, 3>(), array<i32, 2>());
     WrapInFunction(t);
@@ -809,19 +812,19 @@
               R"(error: 'array<i32, 3>' cannot be used to construct an array of 'array<i32, 2>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayOfArray_SubElemSizeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayOfArray_SubElemSizeMismatch) {
     // array<array<i32, 2u>, 2u>(array<i32, 3u>(), array<i32, 2u>());
     auto* t = array<Infer>(Source{{12, 34}}, array<i32, 3>(), array<i32, 2>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'array<i32, 3>'
 note: argument 1 is of type 'array<i32, 2>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, ArrayOfArray_SubElemTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, ArrayOfArray_SubElemTypeMismatch) {
     // array<array<i32, 2u>, 2u>(array<i32, 2u>(), array<u32, 2u>());
     auto* t = array(Source{{12, 34}}, ty.array<i32, 2>(), 2_i, array<i32, 2>(), array<u32, 2>());
     WrapInFunction(t);
@@ -831,19 +834,19 @@
               R"(error: 'array<u32, 2>' cannot be used to construct an array of 'array<i32, 2>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferredArrayOfArray_SubElemTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, InferredArrayOfArray_SubElemTypeMismatch) {
     // array<array<i32, 2u>, 2u>(array<i32, 2u>(), array<u32, 2u>());
     auto* t = array<Infer>(Source{{12, 34}}, array<i32, 2>(), array<u32, 2>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot infer common array element type from initializer arguments
+              R"(12:34 error: cannot infer common array element type from constructor arguments
 note: argument 0 is of type 'array<i32, 2>'
 note: argument 1 is of type 'array<u32, 2>')");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Array_TooFewElements) {
+TEST_F(ResolverValueConstructorValidationTest, Array_TooFewElements) {
     // array<i32, 4u>(1i, 2i, 3i);
     SetSource(Source::Location({12, 34}));
     auto* tc = array<i32, 4>(Expr(1_i), Expr(2_i), Expr(3_i));
@@ -851,10 +854,10 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array initializer has too few elements: expected 4, found 3");
+              "12:34 error: array constructor has too few elements: expected 4, found 3");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Array_TooManyElements) {
+TEST_F(ResolverValueConstructorValidationTest, Array_TooManyElements) {
     // array<i32, 4u>(1i, 2i, 3i, 4i, 5i);
     SetSource(Source::Location({12, 34}));
     auto* tc = array<i32, 4>(Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i), Expr(5_i));
@@ -862,12 +865,12 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array initializer has too many "
+              "12:34 error: array constructor has too many "
               "elements: expected 4, "
               "found 5");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Array_Runtime) {
+TEST_F(ResolverValueConstructorValidationTest, Array_Runtime) {
     // array<i32>(1i);
     auto* tc = array<i32>(Source{{12, 34}}, Expr(1_i));
     WrapInFunction(tc);
@@ -876,7 +879,7 @@
     EXPECT_EQ(r()->error(), "12:34 error: cannot construct a runtime-sized array");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Array_RuntimeZeroValue) {
+TEST_F(ResolverValueConstructorValidationTest, Array_RuntimeZeroValue) {
     // array<i32>();
     auto* tc = array<i32>(Source{{12, 34}});
     WrapInFunction(tc);
@@ -885,11 +888,11 @@
     EXPECT_EQ(r()->error(), "12:34 error: cannot construct a runtime-sized array");
 }
 
-}  // namespace ArrayInitializer
+}  // namespace ArrayConstructor
 
-namespace ScalarInitializer {
+namespace ScalarConstructor {
 
-TEST_F(ResolverTypeInitializerValidationTest, I32_Success) {
+TEST_F(ResolverValueConstructorValidationTest, I32_Success) {
     auto* expr = Call<i32>(Expr(123_i));
     WrapInFunction(expr);
 
@@ -900,14 +903,14 @@
 
     auto* call = Sem().Get<sem::Call>(expr);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::I32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, U32_Success) {
+TEST_F(ResolverValueConstructorValidationTest, U32_Success) {
     auto* expr = Call<u32>(Expr(123_u));
     WrapInFunction(expr);
 
@@ -918,14 +921,14 @@
 
     auto* call = Sem().Get<sem::Call>(expr);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, F32_Success) {
+TEST_F(ResolverValueConstructorValidationTest, F32_Success) {
     auto* expr = Call<f32>(Expr(1.23_f));
     WrapInFunction(expr);
 
@@ -936,14 +939,14 @@
 
     auto* call = Sem().Get<sem::Call>(expr);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::F32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, F16_Success) {
+TEST_F(ResolverValueConstructorValidationTest, F16_Success) {
     Enable(builtin::Extension::kF16);
 
     auto* expr = Call<f16>(Expr(1.5_h));
@@ -956,14 +959,14 @@
 
     auto* call = Sem().Get<sem::Call>(expr);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::F16>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Convert_f32_to_i32_Success) {
+TEST_F(ResolverValueConstructorValidationTest, Convert_f32_to_i32_Success) {
     auto* expr = Call<i32>(1.23_f);
     WrapInFunction(expr);
 
@@ -974,14 +977,14 @@
 
     auto* call = Sem().Get<sem::Call>(expr);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    auto* ctor = call->Target()->As<sem::ValueConversion>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::F32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Convert_i32_to_u32_Success) {
+TEST_F(ResolverValueConstructorValidationTest, Convert_i32_to_u32_Success) {
     auto* expr = Call<u32>(123_i);
     WrapInFunction(expr);
 
@@ -992,14 +995,14 @@
 
     auto* call = Sem().Get<sem::Call>(expr);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    auto* ctor = call->Target()->As<sem::ValueConversion>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::I32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Convert_u32_to_f16_Success) {
+TEST_F(ResolverValueConstructorValidationTest, Convert_u32_to_f16_Success) {
     Enable(builtin::Extension::kF16);
 
     auto* expr = Call<f16>(123_u);
@@ -1012,14 +1015,14 @@
 
     auto* call = Sem().Get<sem::Call>(expr);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    auto* ctor = call->Target()->As<sem::ValueConversion>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Convert_f16_to_f32_Success) {
+TEST_F(ResolverValueConstructorValidationTest, Convert_f16_to_f32_Success) {
     Enable(builtin::Extension::kF16);
 
     auto* expr = Call<f32>(123_h);
@@ -1032,109 +1035,109 @@
 
     auto* call = Sem().Get<sem::Call>(expr);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    auto* ctor = call->Target()->As<sem::ValueConversion>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::F16>());
 }
 
-}  // namespace ScalarInitializer
+}  // namespace ScalarConstructor
 
-namespace VectorInitializer {
+namespace VectorConstructor {
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2F32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2F32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec2<f32>(Source{{12, 34}}, 1_i, 2_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<f32>(i32, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<f32>(i32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2F16_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2F16_Error_ScalarArgumentTypeMismatch) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec2<f16>(Source{{12, 34}}, 1_h, 2_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<f16>(f16, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<f16>(f16, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2U32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2U32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec2<u32>(Source{{12, 34}}, 1_u, 2_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<u32>(u32, i32)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<u32>(u32, i32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2I32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2I32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec2<i32>(Source{{12, 34}}, 1_u, 2_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<i32>(u32, i32)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<i32>(u32, i32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2Bool_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2Bool_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec2<bool>(Source{{12, 34}}, true, 1_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<bool>(bool, i32)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<bool>(bool, i32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Error_Vec3ArgumentCardinalityTooLarge) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_Vec3ArgumentCardinalityTooLarge) {
     WrapInFunction(vec2<f32>(Source{{12, 34}}, vec3<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<f32>(vec3<f32>)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec3<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Error_Vec4ArgumentCardinalityTooLarge) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_Vec4ArgumentCardinalityTooLarge) {
     WrapInFunction(vec2<f32>(Source{{12, 34}}, vec4<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<f32>(vec4<f32>)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec4<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Error_TooManyArgumentsScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsScalar) {
     WrapInFunction(vec2<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<f32>(f32, f32, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<f32>(f32, f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Error_TooManyArgumentsVector) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsVector) {
     WrapInFunction(vec2<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec2<f32>(vec2<f32>, vec2<f32>)"));
+        HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec2<f32>, vec2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Error_TooManyArgumentsVectorAndScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsVectorAndScalar) {
     WrapInFunction(vec2<f32>(Source{{12, 34}}, vec2<f32>(), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<f32>(vec2<f32>, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec2<f32>, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Error_InvalidArgumentType) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_InvalidArgumentType) {
     WrapInFunction(vec2<f32>(Source{{12, 34}}, mat2x2<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<f32>(mat2x2<f32>)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<f32>(mat2x2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Success_ZeroValue) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Success_ZeroValue) {
     auto* tc = vec2<f32>();
     WrapInFunction(tc);
 
@@ -1147,13 +1150,13 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 0u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2F32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2F32_Success_Scalar) {
     auto* tc = vec2<f32>(1_f, 1_f);
     WrapInFunction(tc);
 
@@ -1166,7 +1169,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -1174,7 +1177,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<type::F32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2F16_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2F16_Success_Scalar) {
     Enable(builtin::Extension::kF16);
 
     auto* tc = vec2<f16>(1_h, 1_h);
@@ -1189,7 +1192,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -1197,7 +1200,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<type::F16>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2U32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2U32_Success_Scalar) {
     auto* tc = vec2<u32>(1_u, 1_u);
     WrapInFunction(tc);
 
@@ -1210,7 +1213,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -1218,7 +1221,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2I32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2I32_Success_Scalar) {
     auto* tc = vec2<i32>(1_i, 1_i);
     WrapInFunction(tc);
 
@@ -1231,7 +1234,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -1239,7 +1242,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<type::I32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2Bool_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2Bool_Success_Scalar) {
     auto* tc = vec2<bool>(true, false);
     WrapInFunction(tc);
 
@@ -1252,7 +1255,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -1260,7 +1263,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<type::Bool>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Success_Identity) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Success_Identity) {
     auto* tc = vec2<f32>(vec2<f32>());
     WrapInFunction(tc);
 
@@ -1273,14 +1276,14 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::Vector>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec2_Success_Vec2TypeConversion) {
+TEST_F(ResolverValueConstructorValidationTest, Vec2_Success_Vec2TypeConversion) {
     auto* tc = vec2<f32>(vec2<i32>());
     WrapInFunction(tc);
 
@@ -1293,123 +1296,123 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    auto* ctor = call->Target()->As<sem::ValueConversion>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::Vector>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3F32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3F32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f, 3_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<f32>(f32, f32, i32)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32, i32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3F16_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3F16_Error_ScalarArgumentTypeMismatch) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(Source{{12, 34}}, 1_h, 2_h, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<f16>(f16, f16, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<f16>(f16, f16, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3U32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3U32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec3<u32>(Source{{12, 34}}, 1_u, 2_i, 3_u));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<u32>(u32, i32, u32)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<u32>(u32, i32, u32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3I32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3I32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec3<i32>(Source{{12, 34}}, 1_i, 2_u, 3_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<i32>(i32, u32, i32)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<i32>(i32, u32, i32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3Bool_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3Bool_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec3<bool>(Source{{12, 34}}, false, 1_i, true));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<bool>(bool, i32, bool)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<bool>(bool, i32, bool)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Error_Vec4ArgumentCardinalityTooLarge) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_Vec4ArgumentCardinalityTooLarge) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, vec4<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<f32>(vec4<f32>)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec4<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Error_TooFewArgumentsScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooFewArgumentsScalar) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<f32>(f32, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Error_TooManyArgumentsScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsScalar) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f, 4_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec3<f32>(f32, f32, f32, f32)"));
+        HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32, f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Error_TooFewArgumentsVec2) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooFewArgumentsVec2) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<f32>(vec2<f32>)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Error_TooManyArgumentsVec2) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec2) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec3<f32>(vec2<f32>, vec2<f32>)"));
+        HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>, vec2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Error_TooManyArgumentsVec2AndScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec2AndScalar) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>(), 1_f, 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec3<f32>(vec2<f32>, f32, f32)"));
+        HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>, f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Error_TooManyArgumentsVec3) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec3) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, vec3<f32>(), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<f32>(vec3<f32>, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec3<f32>, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Error_InvalidArgumentType) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_InvalidArgumentType) {
     WrapInFunction(vec3<f32>(Source{{12, 34}}, mat2x2<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<f32>(mat2x2<f32>)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<f32>(mat2x2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Success_ZeroValue) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_ZeroValue) {
     auto* tc = vec3<f32>();
     WrapInFunction(tc);
 
@@ -1422,13 +1425,13 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 0u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3F32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3F32_Success_Scalar) {
     auto* tc = vec3<f32>(1_f, 1_f, 1_f);
     WrapInFunction(tc);
 
@@ -1441,7 +1444,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -1450,7 +1453,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::F32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3F16_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3F16_Success_Scalar) {
     Enable(builtin::Extension::kF16);
 
     auto* tc = vec3<f16>(1_h, 1_h, 1_h);
@@ -1465,7 +1468,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -1474,7 +1477,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::F16>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3U32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3U32_Success_Scalar) {
     auto* tc = vec3<u32>(1_u, 1_u, 1_u);
     WrapInFunction(tc);
 
@@ -1487,7 +1490,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -1496,7 +1499,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::U32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3I32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3I32_Success_Scalar) {
     auto* tc = vec3<i32>(1_i, 1_i, 1_i);
     WrapInFunction(tc);
 
@@ -1509,7 +1512,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -1518,7 +1521,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::I32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3Bool_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3Bool_Success_Scalar) {
     auto* tc = vec3<bool>(true, false, true);
     WrapInFunction(tc);
 
@@ -1531,7 +1534,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 3u);
@@ -1540,7 +1543,7 @@
     EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<type::Bool>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Success_Vec2AndScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_Vec2AndScalar) {
     auto* tc = vec3<f32>(vec2<f32>(), 1_f);
     WrapInFunction(tc);
 
@@ -1553,7 +1556,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -1561,7 +1564,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<type::F32>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Success_ScalarAndVec2) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_ScalarAndVec2) {
     auto* tc = vec3<f32>(1_f, vec2<f32>());
     WrapInFunction(tc);
 
@@ -1574,7 +1577,7 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 2u);
@@ -1582,7 +1585,7 @@
     EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<type::Vector>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Success_Identity) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_Identity) {
     auto* tc = vec3<f32>(vec3<f32>());
     WrapInFunction(tc);
 
@@ -1595,14 +1598,14 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::Vector>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec3_Success_Vec3TypeConversion) {
+TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_Vec3TypeConversion) {
     auto* tc = vec3<f32>(vec3<i32>());
     WrapInFunction(tc);
 
@@ -1615,23 +1618,23 @@
 
     auto* call = Sem().Get<sem::Call>(tc);
     ASSERT_NE(call, nullptr);
-    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    auto* ctor = call->Target()->As<sem::ValueConversion>();
     ASSERT_NE(ctor, nullptr);
     EXPECT_EQ(call->Type(), ctor->ReturnType());
     ASSERT_EQ(ctor->Parameters().Length(), 1u);
     EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<type::Vector>());
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4F32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4F32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 1_f, 1_i, 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f32>(f32, f32, i32, f32)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, i32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4F16_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4F16_Error_ScalarArgumentTypeMismatch) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec4<f16>(Source{{12, 34}}, 1_h, 1_h, 1_f, 1_h));
@@ -1639,142 +1642,142 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f16>(f16, f16, f32, f16)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f16>(f16, f16, f32, f16)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4U32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4U32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec4<u32>(Source{{12, 34}}, 1_u, 1_u, 1_i, 1_u));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<u32>(u32, u32, i32, u32)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<u32>(u32, u32, i32, u32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4I32_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4I32_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec4<i32>(Source{{12, 34}}, 1_i, 1_i, 1_u, 1_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<i32>(i32, i32, u32, i32)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<i32>(i32, i32, u32, i32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4Bool_Error_ScalarArgumentTypeMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4Bool_Error_ScalarArgumentTypeMismatch) {
     WrapInFunction(vec4<bool>(Source{{12, 34}}, true, false, 1_i, true));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<bool>(bool, bool, i32, bool)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<bool>(bool, bool, i32, bool)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooFewArgumentsScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsScalar) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec4<f32>(f32, f32, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooManyArgumentsScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsScalar) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f, 4_f, 5_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f32>(f32, f32, f32, f32, f32)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, f32, f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooFewArgumentsVec2AndScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsVec2AndScalar) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec4<f32>(vec2<f32>, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooManyArgumentsVec2AndScalars) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2AndScalars) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), 1_f, 2_f, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f32>(vec2<f32>, f32, f32, f32)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, f32, f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Scalar) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>(), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f32>(vec2<f32>, vec2<f32>, f32)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec2<f32>, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Vec2) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Vec2) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>(), vec2<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
         HasSubstr(
-            "12:34 error: no matching initializer for vec4<f32>(vec2<f32>, vec2<f32>, vec2<f32>)"));
+            "12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec2<f32>, vec2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooFewArgumentsVec3) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsVec3) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec4<f32>(vec3<f32>)"));
+                HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooManyArgumentsVec3AndScalars) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndScalars) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), 1_f, 2_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f32>(vec3<f32>, f32, f32)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec2) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec2) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), vec2<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f32>(vec3<f32>, vec2<f32>)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, vec2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooManyArgumentsVec2AndVec3) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2AndVec3) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec3<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f32>(vec2<f32>, vec3<f32>)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec3<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec3) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec3) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), vec3<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for vec4<f32>(vec3<f32>, vec3<f32>)"));
+        HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, vec3<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Error_InvalidArgumentType) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_InvalidArgumentType) {
     WrapInFunction(vec4<f32>(Source{{12, 34}}, mat2x2<f32>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec4<f32>(mat2x2<f32>)"));
+                HasSubstr("12:34 error: no matching constructor for vec4<f32>(mat2x2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_ZeroValue) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ZeroValue) {
     auto* tc = vec4<f32>();
     WrapInFunction(tc);
 
@@ -1786,7 +1789,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4F32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4F32_Success_Scalar) {
     auto* tc = vec4<f32>(1_f, 1_f, 1_f, 1_f);
     WrapInFunction(tc);
 
@@ -1798,7 +1801,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4F16_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4F16_Success_Scalar) {
     Enable(builtin::Extension::kF16);
 
     auto* tc = vec4<f16>(1_h, 1_h, 1_h, 1_h);
@@ -1812,7 +1815,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4U32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4U32_Success_Scalar) {
     auto* tc = vec4<u32>(1_u, 1_u, 1_u, 1_u);
     WrapInFunction(tc);
 
@@ -1824,7 +1827,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4I32_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4I32_Success_Scalar) {
     auto* tc = vec4<i32>(1_i, 1_i, 1_i, 1_i);
     WrapInFunction(tc);
 
@@ -1836,7 +1839,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4Bool_Success_Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4Bool_Success_Scalar) {
     auto* tc = vec4<bool>(true, false, true, false);
     WrapInFunction(tc);
 
@@ -1848,7 +1851,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_Vec2ScalarScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Vec2ScalarScalar) {
     auto* tc = vec4<f32>(vec2<f32>(), 1_f, 1_f);
     WrapInFunction(tc);
 
@@ -1860,7 +1863,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_ScalarVec2Scalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ScalarVec2Scalar) {
     auto* tc = vec4<f32>(1_f, vec2<f32>(), 1_f);
     WrapInFunction(tc);
 
@@ -1872,7 +1875,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_ScalarScalarVec2) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ScalarScalarVec2) {
     auto* tc = vec4<f32>(1_f, 1_f, vec2<f32>());
     WrapInFunction(tc);
 
@@ -1884,7 +1887,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_Vec2AndVec2) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Vec2AndVec2) {
     auto* tc = vec4<f32>(vec2<f32>(), vec2<f32>());
     WrapInFunction(tc);
 
@@ -1896,7 +1899,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_Vec3AndScalar) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Vec3AndScalar) {
     auto* tc = vec4<f32>(vec3<f32>(), 1_f);
     WrapInFunction(tc);
 
@@ -1908,7 +1911,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_ScalarAndVec3) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ScalarAndVec3) {
     auto* tc = vec4<f32>(1_f, vec3<f32>());
     WrapInFunction(tc);
 
@@ -1920,7 +1923,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_Identity) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Identity) {
     auto* tc = vec4<f32>(vec4<f32>());
     WrapInFunction(tc);
 
@@ -1932,7 +1935,7 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vec4_Success_Vec4TypeConversion) {
+TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Vec4TypeConversion) {
     auto* tc = vec4<f32>(vec4<i32>());
     WrapInFunction(tc);
 
@@ -1944,17 +1947,17 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, NestedVectorInitializers_InnerError) {
+TEST_F(ResolverValueConstructorValidationTest, NestedVectorConstructors_InnerError) {
     WrapInFunction(vec4<f32>(vec4<f32>(1_f, 1_f,  //
                                        vec3<f32>(Source{{12, 34}}, 1_f, 1_f)),
                              1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<f32>(f32, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, NestedVectorInitializers_Success) {
+TEST_F(ResolverValueConstructorValidationTest, NestedVectorConstructors_Success) {
     auto* tc = vec4<f32>(vec3<f32>(vec2<f32>(1_f, 1_f), 1_f), 1_f);
     WrapInFunction(tc);
 
@@ -1966,29 +1969,29 @@
     EXPECT_EQ(TypeOf(tc)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vector_Alias_Argument_Error) {
+TEST_F(ResolverValueConstructorValidationTest, Vector_Alias_Argument_Error) {
     auto* alias = Alias("UnsignedInt", ty.u32());
-    GlobalVar("uint_var", ty.Of(alias), type::AddressSpace::kPrivate);
+    GlobalVar("uint_var", ty.Of(alias), builtin::AddressSpace::kPrivate);
 
     auto* tc = vec2<f32>(Source{{12, 34}}, "uint_var");
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for vec2<f32>(u32)"));
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for vec2<f32>(u32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vector_Alias_Argument_Success) {
+TEST_F(ResolverValueConstructorValidationTest, Vector_Alias_Argument_Success) {
     auto* f32_alias = Alias("Float32", ty.f32());
     auto* vec2_alias = Alias("VectorFloat2", ty.vec2<f32>());
-    GlobalVar("my_f32", ty.Of(f32_alias), type::AddressSpace::kPrivate);
-    GlobalVar("my_vec2", ty.Of(vec2_alias), type::AddressSpace::kPrivate);
+    GlobalVar("my_f32", ty.Of(f32_alias), builtin::AddressSpace::kPrivate);
+    GlobalVar("my_vec2", ty.Of(vec2_alias), builtin::AddressSpace::kPrivate);
 
     auto* tc = vec3<f32>("my_vec2", "my_f32");
     WrapInFunction(tc);
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vector_ElementTypeAlias_Error) {
+TEST_F(ResolverValueConstructorValidationTest, Vector_ElementTypeAlias_Error) {
     auto* f32_alias = Alias("Float32", ty.f32());
 
     // vec2<Float32>(1.0f, 1u)
@@ -1997,10 +2000,10 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec2<f32>(f32, u32)"));
+                HasSubstr("12:34 error: no matching constructor for vec2<f32>(f32, u32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vector_ElementTypeAlias_Success) {
+TEST_F(ResolverValueConstructorValidationTest, Vector_ElementTypeAlias_Success) {
     auto* f32_alias = Alias("Float32", ty.f32());
 
     // vec2<Float32>(1.0f, 1.0f)
@@ -2011,7 +2014,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vector_ArgumentElementTypeAlias_Error) {
+TEST_F(ResolverValueConstructorValidationTest, Vector_ArgumentElementTypeAlias_Error) {
     auto* f32_alias = Alias("Float32", ty.f32());
 
     // vec3<u32>(vec<Float32>(), 1.0f)
@@ -2020,10 +2023,10 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("12:34 error: no matching initializer for vec3<u32>(vec2<f32>, f32)"));
+                HasSubstr("12:34 error: no matching constructor for vec3<u32>(vec2<f32>, f32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Vector_ArgumentElementTypeAlias_Success) {
+TEST_F(ResolverValueConstructorValidationTest, Vector_ArgumentElementTypeAlias_Success) {
     auto* f32_alias = Alias("Float32", ty.f32());
 
     // vec3<f32>(vec<Float32>(), 1.0f)
@@ -2034,7 +2037,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec2ElementTypeFromScalars) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec2ElementTypeFromScalars) {
     Enable(builtin::Extension::kF16);
 
     auto* vec2_bool = vec2<Infer>(true, false);
@@ -2063,7 +2066,7 @@
     EXPECT_EQ(TypeOf(vec2_f16)->As<type::Vector>()->Width(), 2u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec2ElementTypeFromVec2) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec2ElementTypeFromVec2) {
     Enable(builtin::Extension::kF16);
 
     auto* vec2_bool = vec2<Infer>(vec2<bool>(true, false));
@@ -2092,7 +2095,7 @@
     EXPECT_EQ(TypeOf(vec2_f16)->As<type::Vector>()->Width(), 2u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec3ElementTypeFromScalars) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec3ElementTypeFromScalars) {
     Enable(builtin::Extension::kF16);
 
     auto* vec3_bool = vec3<Infer>(Expr(true), Expr(false), Expr(true));
@@ -2121,7 +2124,7 @@
     EXPECT_EQ(TypeOf(vec3_f16)->As<type::Vector>()->Width(), 3u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec3ElementTypeFromVec3) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec3ElementTypeFromVec3) {
     Enable(builtin::Extension::kF16);
 
     auto* vec3_bool = vec3<Infer>(vec3<bool>(true, false, true));
@@ -2150,7 +2153,7 @@
     EXPECT_EQ(TypeOf(vec3_f16)->As<type::Vector>()->Width(), 3u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec3ElementTypeFromScalarAndVec2) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec3ElementTypeFromScalarAndVec2) {
     Enable(builtin::Extension::kF16);
 
     auto* vec3_bool = vec3<Infer>(Expr(true), vec2<bool>(false, true));
@@ -2179,7 +2182,7 @@
     EXPECT_EQ(TypeOf(vec3_f16)->As<type::Vector>()->Width(), 3u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec4ElementTypeFromScalars) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec4ElementTypeFromScalars) {
     Enable(builtin::Extension::kF16);
 
     auto* vec4_bool = vec4<Infer>(Expr(true), Expr(false), Expr(true), Expr(false));
@@ -2208,7 +2211,7 @@
     EXPECT_EQ(TypeOf(vec4_f16)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec4ElementTypeFromVec4) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec4ElementTypeFromVec4) {
     Enable(builtin::Extension::kF16);
 
     auto* vec4_bool = vec4<Infer>(vec4<bool>(true, false, true, false));
@@ -2237,7 +2240,7 @@
     EXPECT_EQ(TypeOf(vec4_f16)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec4ElementTypeFromScalarAndVec3) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec4ElementTypeFromScalarAndVec3) {
     Enable(builtin::Extension::kF16);
 
     auto* vec4_bool = vec4<Infer>(Expr(true), vec3<bool>(false, true, false));
@@ -2266,7 +2269,7 @@
     EXPECT_EQ(TypeOf(vec4_f16)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, InferVec4ElementTypeFromVec2AndVec2) {
+TEST_F(ResolverValueConstructorValidationTest, InferVec4ElementTypeFromVec2AndVec2) {
     Enable(builtin::Extension::kF16);
 
     auto* vec4_bool = vec4<Infer>(vec2<bool>(true, false), vec2<bool>(true, false));
@@ -2295,23 +2298,23 @@
     EXPECT_EQ(TypeOf(vec4_f16)->As<type::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, CannotInferVectorElementTypeWithoutArgs) {
+TEST_F(ResolverValueConstructorValidationTest, CannotInferVectorElementTypeWithoutArgs) {
     WrapInFunction(Call(Source{{12, 34}}, "vec3"));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for vec3()"));
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for vec3()"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, CannotInferVec2ElementTypeFromScalarsMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, CannotInferVec2ElementTypeFromScalarsMismatch) {
     WrapInFunction(Call(Source{{1, 1}}, "vec2",     //
                         Expr(Source{{1, 2}}, 1_i),  //
                         Expr(Source{{1, 3}}, 2_u)));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("1:1 error: no matching initializer for vec2(i32, u32)"));
+    EXPECT_THAT(r()->error(), HasSubstr("1:1 error: no matching constructor for vec2(i32, u32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, CannotInferVec3ElementTypeFromScalarsMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, CannotInferVec3ElementTypeFromScalarsMismatch) {
     WrapInFunction(Call(Source{{1, 1}}, "vec3",     //
                         Expr(Source{{1, 2}}, 1_i),  //
                         Expr(Source{{1, 3}}, 2_u),  //
@@ -2319,20 +2322,21 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("1:1 error: no matching initializer for vec3(i32, u32, i32)"));
+                HasSubstr("1:1 error: no matching constructor for vec3(i32, u32, i32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, CannotInferVec3ElementTypeFromScalarAndVec2Mismatch) {
+TEST_F(ResolverValueConstructorValidationTest,
+       CannotInferVec3ElementTypeFromScalarAndVec2Mismatch) {
     WrapInFunction(Call(Source{{1, 1}}, "vec3",     //
                         Expr(Source{{1, 2}}, 1_i),  //
                         Call(Source{{1, 3}}, ty.vec2<f32>(), 2_f, 3_f)));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("1:1 error: no matching initializer for vec3(i32, vec2<f32>)"));
+                HasSubstr("1:1 error: no matching constructor for vec3(i32, vec2<f32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, CannotInferVec4ElementTypeFromScalarsMismatch) {
+TEST_F(ResolverValueConstructorValidationTest, CannotInferVec4ElementTypeFromScalarsMismatch) {
     WrapInFunction(Call(Source{{1, 1}}, "vec4",     //
                         Expr(Source{{1, 2}}, 1_i),  //
                         Expr(Source{{1, 3}}, 2_i),  //
@@ -2341,32 +2345,33 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("1:1 error: no matching initializer for vec4(i32, i32, f32, i32)"));
+                HasSubstr("1:1 error: no matching constructor for vec4(i32, i32, f32, i32)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, CannotInferVec4ElementTypeFromScalarAndVec3Mismatch) {
+TEST_F(ResolverValueConstructorValidationTest,
+       CannotInferVec4ElementTypeFromScalarAndVec3Mismatch) {
     WrapInFunction(Call(Source{{1, 1}}, "vec4",     //
                         Expr(Source{{1, 2}}, 1_i),  //
                         Call(Source{{1, 3}}, ty.vec3<u32>(), 2_u, 3_u, 4_u)));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("1:1 error: no matching initializer for vec4(i32, vec3<u32>)"));
+                HasSubstr("1:1 error: no matching constructor for vec4(i32, vec3<u32>)"));
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, CannotInferVec4ElementTypeFromVec2AndVec2Mismatch) {
+TEST_F(ResolverValueConstructorValidationTest, CannotInferVec4ElementTypeFromVec2AndVec2Mismatch) {
     WrapInFunction(Call(Source{{1, 1}}, "vec4",                          //
                         Call(Source{{1, 2}}, ty.vec2<i32>(), 3_i, 4_i),  //
                         Call(Source{{1, 3}}, ty.vec2<u32>(), 3_u, 4_u)));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
-                HasSubstr("1:1 error: no matching initializer for vec4(vec2<i32>, vec2<u32>)"));
+                HasSubstr("1:1 error: no matching constructor for vec4(vec2<i32>, vec2<u32>)"));
 }
 
-}  // namespace VectorInitializer
+}  // namespace VectorConstructor
 
-namespace MatrixInitializer {
+namespace MatrixConstructor {
 
 struct MatrixParams {
     using name_func_ptr = std::string (*)();
@@ -2398,9 +2403,9 @@
            param.get_element_type_name() + ">";
 }
 
-using MatrixInitializerTest = ResolverTestWithParam<MatrixParams>;
+using MatrixConstructorTest = ResolverTestWithParam<MatrixParams>;
 
-TEST_P(MatrixInitializerTest, ColumnInitializer_Error_TooFewArguments) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewArguments) {
     // matNxM<f32>(vecM<f32>(), ...); with N - 1 arguments
     // matNxM<f16>(vecM<f16>(), ...); with N - 1 arguments
 
@@ -2425,11 +2430,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ElementInitializer_Error_TooFewArguments) {
+TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooFewArguments) {
     // matNxM<f32>(f32,...,f32); with N*M - 1 arguments
     // matNxM<f16>(f16,...,f16); with N*M - 1 arguments
 
@@ -2453,11 +2458,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ColumnInitializer_Error_TooManyArguments) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyArguments) {
     // matNxM<f32>(vecM<f32>(), ...); with N + 1 arguments
     // matNxM<f16>(vecM<f16>(), ...); with N + 1 arguments
 
@@ -2482,11 +2487,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ElementInitializer_Error_TooManyArguments) {
+TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooManyArguments) {
     // matNxM<f32>(f32,...,f32); with N*M + 1 arguments
     // matNxM<f16>(f16,...,f16); with N*M + 1 arguments
 
@@ -2510,11 +2515,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ColumnInitializer_Error_InvalidArgumentType) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_InvalidArgumentType) {
     // matNxM<f32>(vec<u32>, vec<u32>, ...); N arguments
     // matNxM<f16>(vec<u32>, vec<u32>, ...); N arguments
 
@@ -2538,11 +2543,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ElementInitializer_Error_InvalidArgumentType) {
+TEST_P(MatrixConstructorTest, ElementConstructor_Error_InvalidArgumentType) {
     // matNxM<f32>(u32, u32, ...); N*M arguments
     // matNxM<f16>(u32, u32, ...); N*M arguments
 
@@ -2565,11 +2570,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ColumnInitializer_Error_TooFewRowsInVectorArgument) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewRowsInVectorArgument) {
     // matNxM<f32>(vecM<f32>(),...,vecM-1<f32>());
     // matNxM<f16>(vecM<f16>(),...,vecM-1<f32>());
 
@@ -2603,11 +2608,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ColumnInitializer_Error_TooManyRowsInVectorArgument) {
+TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyRowsInVectorArgument) {
     // matNxM<f32>(vecM<f32>(),...,vecM+1<f32>());
     // matNxM<f16>(vecM<f16>(),...,vecM+1<f16>());
 
@@ -2640,11 +2645,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ZeroValue_Success) {
+TEST_P(MatrixConstructorTest, ZeroValue_Success) {
     // matNxM<f32>();
     // matNxM<f16>();
 
@@ -2659,7 +2664,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_P(MatrixInitializerTest, WithColumns_Success) {
+TEST_P(MatrixConstructorTest, WithColumns_Success) {
     // matNxM<f32>(vecM<f32>(), ...); with N arguments
     // matNxM<f16>(vecM<f16>(), ...); with N arguments
 
@@ -2680,7 +2685,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_P(MatrixInitializerTest, WithElements_Success) {
+TEST_P(MatrixConstructorTest, WithElements_Success) {
     // matNxM<f32>(f32,...,f32); with N*M arguments
     // matNxM<f16>(f16,...,f16); with N*M arguments
 
@@ -2700,7 +2705,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_P(MatrixInitializerTest, ElementTypeAlias_Error) {
+TEST_P(MatrixConstructorTest, ElementTypeAlias_Error) {
     // matNxM<Float32>(vecM<u32>(), ...); with N arguments
     // matNxM<Float16>(vecM<u32>(), ...); with N arguments
 
@@ -2726,11 +2731,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ElementTypeAlias_Success) {
+TEST_P(MatrixConstructorTest, ElementTypeAlias_Success) {
     // matNxM<Float32>(vecM<f32>(), ...); with N arguments
     // matNxM<Float16>(vecM<f16>(), ...); with N arguments
 
@@ -2753,7 +2758,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, MatrixInitializer_ArgumentTypeAlias_Error) {
+TEST_F(ResolverValueConstructorValidationTest, MatrixConstructor_ArgumentTypeAlias_Error) {
     auto* alias = Alias("VectorUnsigned2", ty.vec2<u32>());
     auto* tc = Call(Source{{12, 34}}, ty.mat2x2<f32>(), Call(ty.Of(alias)), vec2<f32>());
     WrapInFunction(tc);
@@ -2761,10 +2766,10 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
         r()->error(),
-        HasSubstr("12:34 error: no matching initializer for mat2x2<f32>(vec2<u32>, vec2<f32>)"));
+        HasSubstr("12:34 error: no matching constructor for mat2x2<f32>(vec2<u32>, vec2<f32>)"));
 }
 
-TEST_P(MatrixInitializerTest, ArgumentTypeAlias_Success) {
+TEST_P(MatrixConstructorTest, ArgumentTypeAlias_Success) {
     const auto param = GetParam();
 
     Enable(builtin::Extension::kF16);
@@ -2784,7 +2789,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_P(MatrixInitializerTest, ArgumentElementTypeAlias_Error) {
+TEST_P(MatrixConstructorTest, ArgumentElementTypeAlias_Error) {
     const auto param = GetParam();
 
     Enable(builtin::Extension::kF16);
@@ -2807,11 +2812,11 @@
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching initializer for " +
+    EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
                                         MatrixStr(param) + "(" + args_tys.str() + ")"));
 }
 
-TEST_P(MatrixInitializerTest, ArgumentElementTypeAlias_Success) {
+TEST_P(MatrixConstructorTest, ArgumentElementTypeAlias_Success) {
     const auto param = GetParam();
 
     Enable(builtin::Extension::kF16);
@@ -2831,7 +2836,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_P(MatrixInitializerTest, InferElementTypeFromVectors) {
+TEST_P(MatrixConstructorTest, InferElementTypeFromVectors) {
     const auto param = GetParam();
 
     Enable(builtin::Extension::kF16);
@@ -2848,7 +2853,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_P(MatrixInitializerTest, InferElementTypeFromScalars) {
+TEST_P(MatrixConstructorTest, InferElementTypeFromScalars) {
     const auto param = GetParam();
 
     Enable(builtin::Extension::kF16);
@@ -2864,13 +2869,13 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_P(MatrixInitializerTest, CannotInferElementTypeFromVectors_Mismatch) {
+TEST_P(MatrixConstructorTest, CannotInferElementTypeFromVectors_Mismatch) {
     const auto param = GetParam();
 
     Enable(builtin::Extension::kF16);
 
     std::stringstream err;
-    err << "12:34 error: no matching initializer for mat" << param.columns << "x" << param.rows
+    err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows
         << "(";
 
     utils::Vector<const ast::Expression*, 8> args;
@@ -2895,13 +2900,13 @@
     EXPECT_THAT(r()->error(), HasSubstr(err.str()));
 }
 
-TEST_P(MatrixInitializerTest, CannotInferElementTypeFromScalars_Mismatch) {
+TEST_P(MatrixConstructorTest, CannotInferElementTypeFromScalars_Mismatch) {
     const auto param = GetParam();
 
     Enable(builtin::Extension::kF16);
 
     std::stringstream err;
-    err << "12:34 error: no matching initializer for mat" << param.columns << "x" << param.rows
+    err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows
         << "(";
 
     utils::Vector<const ast::Expression*, 16> args;
@@ -2927,8 +2932,8 @@
     EXPECT_THAT(r()->error(), HasSubstr(err.str()));
 }
 
-INSTANTIATE_TEST_SUITE_P(ResolverTypeInitializerValidationTest,
-                         MatrixInitializerTest,
+INSTANTIATE_TEST_SUITE_P(ResolverValueConstructorValidationTest,
+                         MatrixConstructorTest,
                          testing::Values(MatrixParamsFor<f32, 2, 2>(),
                                          MatrixParamsFor<f32, 3, 2>(),
                                          MatrixParamsFor<f32, 4, 2>(),
@@ -2947,9 +2952,9 @@
                                          MatrixParamsFor<f16, 2, 4>(),
                                          MatrixParamsFor<f16, 3, 4>(),
                                          MatrixParamsFor<f16, 4, 4>()));
-}  // namespace MatrixInitializer
+}  // namespace MatrixConstructor
 
-namespace StructInitializer {
+namespace StructConstructor {
 using builder::CreatePtrs;
 using builder::CreatePtrsFor;
 using builder::mat2x2;
@@ -2980,10 +2985,10 @@
 
 auto number_of_members = testing::Values(2u, 32u, 64u);
 
-using StructInitializerInputsTest =
+using StructConstructorInputsTest =
     ResolverTestWithParam<std::tuple<CreatePtrs,  // struct member type
                                      uint32_t>>;  // number of struct members
-TEST_P(StructInitializerInputsTest, TooFew) {
+TEST_P(StructConstructorInputsTest, TooFew) {
     auto& param = GetParam();
     auto& str_params = std::get<0>(param);
     uint32_t N = std::get<1>(param);
@@ -3004,11 +3009,11 @@
     auto* tc = Call(Source{{12, 34}}, ty.Of(s), values);
     WrapInFunction(tc);
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: struct initializer has too few inputs: expected " +
+    EXPECT_EQ(r()->error(), "12:34 error: structure constructor has too few inputs: expected " +
                                 std::to_string(N) + ", found " + std::to_string(N - 1));
 }
 
-TEST_P(StructInitializerInputsTest, TooMany) {
+TEST_P(StructConstructorInputsTest, TooMany) {
     auto& param = GetParam();
     auto& str_params = std::get<0>(param);
     uint32_t N = std::get<1>(param);
@@ -3029,18 +3034,18 @@
     auto* tc = Call(Source{{12, 34}}, ty.Of(s), values);
     WrapInFunction(tc);
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: struct initializer has too many inputs: expected " +
+    EXPECT_EQ(r()->error(), "12:34 error: structure constructor has too many inputs: expected " +
                                 std::to_string(N) + ", found " + std::to_string(N + 1));
 }
 
-INSTANTIATE_TEST_SUITE_P(ResolverTypeInitializerValidationTest,
-                         StructInitializerInputsTest,
+INSTANTIATE_TEST_SUITE_P(ResolverValueConstructorValidationTest,
+                         StructConstructorInputsTest,
                          testing::Combine(testing::ValuesIn(all_types), number_of_members));
-using StructInitializerTypeTest =
+using StructConstructorTypeTest =
     ResolverTestWithParam<std::tuple<CreatePtrs,  // struct member type
-                                     CreatePtrs,  // initializer value type
+                                     CreatePtrs,  // constructor value type
                                      uint32_t>>;  // number of struct members
-TEST_P(StructInitializerTypeTest, AllTypes) {
+TEST_P(StructConstructorTypeTest, AllTypes) {
     auto& param = GetParam();
     auto& str_params = std::get<0>(param);
     auto& ctor_params = std::get<1>(param);
@@ -3054,12 +3059,12 @@
 
     utils::Vector<const ast::StructMember*, 16> members;
     utils::Vector<const ast::Expression*, 8> values;
-    // make the last value of the initializer to have a different type
-    uint32_t initializer_value_with_different_type = N - 1;
+    // make the last value of the constructor to have a different type
+    uint32_t constructor_value_with_different_type = N - 1;
     for (uint32_t i = 0; i < N; i++) {
         ast::Type struct_type = str_params.ast(*this);
         members.Push(Member("member_" + std::to_string(i), struct_type));
-        auto* ctor_value_expr = (i == initializer_value_with_different_type)
+        auto* ctor_value_expr = (i == constructor_value_with_different_type)
                                     ? ctor_params.expr_from_double(*this, 0)
                                     : str_params.expr_from_double(*this, 0);
         values.Push(ctor_value_expr);
@@ -3069,19 +3074,19 @@
     WrapInFunction(tc);
 
     std::stringstream err;
-    err << "error: type in struct initializer does not match struct member ";
+    err << "error: type in structure constructor does not match struct member ";
     err << "type: expected '" << str_params.name() << "', found '" << ctor_params.name() << "'";
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), err.str());
 }
 
-INSTANTIATE_TEST_SUITE_P(ResolverTypeInitializerValidationTest,
-                         StructInitializerTypeTest,
+INSTANTIATE_TEST_SUITE_P(ResolverValueConstructorValidationTest,
+                         StructConstructorTypeTest,
                          testing::Combine(testing::ValuesIn(all_types),
                                           testing::ValuesIn(all_types),
                                           number_of_members));
 
-TEST_F(ResolverTypeInitializerValidationTest, Struct_Nested) {
+TEST_F(ResolverValueConstructorValidationTest, Struct_Nested) {
     auto* inner_m = Member("m", ty.i32());
     auto* inner_s = Structure("inner_s", utils::Vector{inner_m});
 
@@ -3094,11 +3099,11 @@
     WrapInFunction(tc);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "error: type in struct initializer does not match struct member "
+              "error: type in structure constructor does not match struct member "
               "type: expected 'inner_s', found 'i32'");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Struct) {
+TEST_F(ResolverValueConstructorValidationTest, Struct) {
     auto* m = Member("m", ty.i32());
     auto* s = Structure("MyInputs", utils::Vector{m});
     auto* tc = Call(Source{{12, 34}}, ty.Of(s));
@@ -3106,7 +3111,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, Struct_Empty) {
+TEST_F(ResolverValueConstructorValidationTest, Struct_Empty) {
     auto* str = Structure("S", utils::Vector{
                                    Member("a", ty.i32()),
                                    Member("b", ty.f32()),
@@ -3116,31 +3121,31 @@
     WrapInFunction(Call(ty.Of(str)));
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
-}  // namespace StructInitializer
+}  // namespace StructConstructor
 
-TEST_F(ResolverTypeInitializerValidationTest, NonConstructibleType_Atomic) {
+TEST_F(ResolverValueConstructorValidationTest, NonConstructibleType_Atomic) {
     WrapInFunction(Assign(Phony(), Call(Source{{12, 34}}, ty.atomic(ty.i32()))));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, NonConstructibleType_AtomicArray) {
+TEST_F(ResolverValueConstructorValidationTest, NonConstructibleType_AtomicArray) {
     WrapInFunction(Assign(Phony(), Call(Source{{12, 34}}, ty.array(ty.atomic(ty.i32()), 4_i))));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: array initializer has non-constructible element type");
+    EXPECT_EQ(r()->error(), "12:34 error: array constructor has non-constructible element type");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, NonConstructibleType_AtomicStructMember) {
+TEST_F(ResolverValueConstructorValidationTest, NonConstructibleType_AtomicStructMember) {
     auto* str = Structure("S", utils::Vector{Member("a", ty.atomic(ty.i32()))});
     WrapInFunction(Assign(Phony(), Call(Source{{12, 34}}, ty.Of(str))));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: struct initializer has non-constructible type");
+    EXPECT_EQ(r()->error(), "12:34 error: structure constructor has non-constructible type");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, NonConstructibleType_Sampler) {
+TEST_F(ResolverValueConstructorValidationTest, NonConstructibleType_Sampler) {
     WrapInFunction(
         Assign(Phony(), Call(Source{{12, 34}}, ty.sampler(type::SamplerKind::kSampler))));
 
@@ -3148,42 +3153,42 @@
     EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, BuilinTypeInitializerAsStatement) {
+TEST_F(ResolverValueConstructorValidationTest, BuilinTypeConstructorAsStatement) {
     WrapInFunction(CallStmt(vec2<f32>(Source{{12, 34}}, 1_f, 2_f)));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: type initializer evaluated but not used");
+    EXPECT_EQ(r()->error(), "12:34 error: value constructor evaluated but not used");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, StructInitializerAsStatement) {
+TEST_F(ResolverValueConstructorValidationTest, StructConstructorAsStatement) {
     Structure("S", utils::Vector{Member("m", ty.i32())});
     WrapInFunction(CallStmt(Call(Source{{12, 34}}, "S", 1_a)));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: type initializer evaluated but not used");
+    EXPECT_EQ(r()->error(), "12:34 error: value constructor evaluated but not used");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, AliasInitializerAsStatement) {
+TEST_F(ResolverValueConstructorValidationTest, AliasConstructorAsStatement) {
     Alias("A", ty.i32());
     WrapInFunction(CallStmt(Call(Source{{12, 34}}, "A", 1_i)));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: type initializer evaluated but not used");
+    EXPECT_EQ(r()->error(), "12:34 error: value constructor evaluated but not used");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, BuilinTypeConversionAsStatement) {
+TEST_F(ResolverValueConstructorValidationTest, BuilinTypeConversionAsStatement) {
     WrapInFunction(CallStmt(Call(Source{{12, 34}}, ty.f32(), 1_i)));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: type conversion evaluated but not used");
+    EXPECT_EQ(r()->error(), "12:34 error: value conversion evaluated but not used");
 }
 
-TEST_F(ResolverTypeInitializerValidationTest, AliasConversionAsStatement) {
+TEST_F(ResolverValueConstructorValidationTest, AliasConversionAsStatement) {
     Alias("A", ty.i32());
     WrapInFunction(CallStmt(Call(Source{{12, 34}}, "A", 1_f)));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: type conversion evaluated but not used");
+    EXPECT_EQ(r()->error(), "12:34 error: value conversion evaluated but not used");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/variable_test.cc b/src/tint/resolver/variable_test.cc
index 2239945..7af6027 100644
--- a/src/tint/resolver/variable_test.cc
+++ b/src/tint/resolver/variable_test.cc
@@ -149,12 +149,12 @@
     ASSERT_TRUE(TypeOf(s)->Is<type::Reference>());
     ASSERT_TRUE(TypeOf(a)->Is<type::Reference>());
 
-    EXPECT_EQ(TypeOf(i)->As<type::Reference>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(u)->As<type::Reference>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(f)->As<type::Reference>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(b)->As<type::Reference>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(s)->As<type::Reference>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(a)->As<type::Reference>()->Access(), type::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(i)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(u)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(f)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(b)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(s)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(a)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
 
     EXPECT_TRUE(TypeOf(i)->As<type::Reference>()->StoreType()->Is<type::I32>());
     EXPECT_TRUE(TypeOf(u)->As<type::Reference>()->StoreType()->Is<type::U32>());
@@ -238,7 +238,7 @@
     //   var a = a;
     // }
 
-    auto* g = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* g = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* v = Var("a", Expr("a"));
     Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v)});
 
@@ -421,7 +421,7 @@
     auto* b = Let("b", ty.bool_(), b_c);
     auto* s = Let("s", ty.Of(S), s_c);
     auto* a = Let("a", ty.Of(A), a_c);
-    auto* p = Let("p", ty.pointer<i32>(type::AddressSpace::kFunction), p_c);
+    auto* p = Let("p", ty.pointer<i32>(builtin::AddressSpace::kFunction), p_c);
 
     Func("F", utils::Empty, ty.void_(),
          utils::Vector{
@@ -472,8 +472,8 @@
     // }
     auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
     auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
-    auto* storage = GlobalVar("s", ty.Of(buf), type::AddressSpace::kStorage,
-                              type::Access::kReadWrite, Binding(0_a), Group(0_a));
+    auto* storage = GlobalVar("s", ty.Of(buf), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite, Binding(0_a), Group(0_a));
 
     auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 3_i);
     auto* ptr = Let("p", AddressOf(expr));
@@ -485,8 +485,8 @@
     ASSERT_TRUE(TypeOf(expr)->Is<type::Reference>());
     ASSERT_TRUE(TypeOf(ptr)->Is<type::Pointer>());
 
-    EXPECT_EQ(TypeOf(expr)->As<type::Reference>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(ptr)->As<type::Pointer>()->Access(), type::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(expr)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(ptr)->As<type::Pointer>()->Access(), builtin::Access::kReadWrite);
 }
 
 TEST_F(ResolverVariableTest, LocalLet_ShadowsAlias) {
@@ -554,7 +554,7 @@
     //   let a = a;
     // }
 
-    auto* g = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* g = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* l = Let("a", Expr("a"));
     Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(l)});
 
@@ -766,7 +766,7 @@
     //   const a = 1i;
     // }
 
-    auto* g = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* g = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* c = Const("a", Expr(1_i));
     Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(c)});
 
@@ -1037,12 +1037,12 @@
     // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
 
     auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
-    auto* private_ = GlobalVar("p", ty.i32(), type::AddressSpace::kPrivate);
-    auto* workgroup = GlobalVar("w", ty.i32(), type::AddressSpace::kWorkgroup);
+    auto* private_ = GlobalVar("p", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* workgroup = GlobalVar("w", ty.i32(), builtin::AddressSpace::kWorkgroup);
     auto* uniform =
-        GlobalVar("ub", ty.Of(buf), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
+        GlobalVar("ub", ty.Of(buf), builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
     auto* storage =
-        GlobalVar("sb", ty.Of(buf), type::AddressSpace::kStorage, Binding(1_a), Group(0_a));
+        GlobalVar("sb", ty.Of(buf), builtin::AddressSpace::kStorage, Binding(1_a), Group(0_a));
     auto* handle =
         GlobalVar("h", ty.depth_texture(type::TextureDimension::k2d), Binding(2_a), Group(0_a));
 
@@ -1054,25 +1054,25 @@
     ASSERT_TRUE(TypeOf(storage)->Is<type::Reference>());
     ASSERT_TRUE(TypeOf(handle)->Is<type::Reference>());
 
-    EXPECT_EQ(TypeOf(private_)->As<type::Reference>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(workgroup)->As<type::Reference>()->Access(), type::Access::kReadWrite);
-    EXPECT_EQ(TypeOf(uniform)->As<type::Reference>()->Access(), type::Access::kRead);
-    EXPECT_EQ(TypeOf(storage)->As<type::Reference>()->Access(), type::Access::kRead);
-    EXPECT_EQ(TypeOf(handle)->As<type::Reference>()->Access(), type::Access::kRead);
+    EXPECT_EQ(TypeOf(private_)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(workgroup)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(uniform)->As<type::Reference>()->Access(), builtin::Access::kRead);
+    EXPECT_EQ(TypeOf(storage)->As<type::Reference>()->Access(), builtin::Access::kRead);
+    EXPECT_EQ(TypeOf(handle)->As<type::Reference>()->Access(), builtin::Access::kRead);
 }
 
 TEST_F(ResolverVariableTest, GlobalVar_ExplicitAddressSpace) {
     // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
 
     auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
-    auto* storage = GlobalVar("sb", ty.Of(buf), type::AddressSpace::kStorage,
-                              type::Access::kReadWrite, Binding(1_a), Group(0_a));
+    auto* storage = GlobalVar("sb", ty.Of(buf), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite, Binding(1_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     ASSERT_TRUE(TypeOf(storage)->Is<type::Reference>());
 
-    EXPECT_EQ(TypeOf(storage)->As<type::Reference>()->Access(), type::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(storage)->As<type::Reference>()->Access(), builtin::Access::kReadWrite);
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1222,7 +1222,7 @@
     // fn F(a : bool) {
     // }
 
-    auto* g = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* g = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* p = Param("a", ty.bool_());
     Func("F", utils::Vector{p}, ty.void_(), utils::Empty);
 
diff --git a/src/tint/resolver/variable_validation_test.cc b/src/tint/resolver/variable_validation_test.cc
index 738d926..6ca3a08 100644
--- a/src/tint/resolver/variable_validation_test.cc
+++ b/src/tint/resolver/variable_validation_test.cc
@@ -61,8 +61,8 @@
 TEST_F(ResolverVariableValidationTest, GlobalVarUsedAtModuleScope) {
     // var<private> a : i32;
     // var<private> b : i32 = a;
-    GlobalVar(Source{{12, 34}}, "a", ty.i32(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.i32(), type::AddressSpace::kPrivate, Expr(Source{{56, 78}}, "a"));
+    GlobalVar(Source{{12, 34}}, "a", ty.i32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.i32(), builtin::AddressSpace::kPrivate, Expr(Source{{56, 78}}, "a"));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(56:78 error: var 'a' cannot be referenced at module-scope
@@ -112,8 +112,8 @@
     // var i : i32;
     // var p : pointer<function, i32> = &v;
     auto* i = Var("i", ty.i32());
-    auto* p = Var("a", ty.pointer<i32>(Source{{56, 78}}, type::AddressSpace::kFunction),
-                  type::AddressSpace::kNone, AddressOf(Source{{12, 34}}, "i"));
+    auto* p = Var("a", ty.pointer<i32>(Source{{56, 78}}, builtin::AddressSpace::kFunction),
+                  builtin::AddressSpace::kUndefined, AddressOf(Source{{12, 34}}, "i"));
     WrapInFunction(i, p);
 
     EXPECT_FALSE(r()->Resolve());
@@ -205,7 +205,7 @@
 TEST_F(ResolverVariableValidationTest, LetOfPtrConstructedWithRef) {
     // var a : f32;
     // let b : ptr<function,f32> = a;
-    const auto priv = type::AddressSpace::kFunction;
+    const auto priv = builtin::AddressSpace::kFunction;
     auto* var_a = Var("a", ty.f32(), priv);
     auto* var_b = Let(Source{{12, 34}}, "b", ty.pointer<f32>(priv), Expr("a"));
     WrapInFunction(var_a, var_b);
@@ -236,7 +236,7 @@
     //   return 0;
     // }
 
-    GlobalVar("v", ty.f32(), type::AddressSpace::kPrivate, Expr(2.1_f));
+    GlobalVar("v", ty.f32(), builtin::AddressSpace::kPrivate, Expr(2.1_f));
 
     WrapInFunction(Var(Source{{12, 34}}, "v", ty.f32(), Expr(2_f)));
 
@@ -295,11 +295,11 @@
                                    Member("inner", ty.Of(inner)),
                                });
     auto* storage =
-        GlobalVar("s", ty.Of(buf), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
+        GlobalVar("s", ty.Of(buf), builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
     auto* ptr = Let(Source{{12, 34}}, "p",
-                    ty.pointer<i32>(type::AddressSpace::kStorage, type::Access::kReadWrite),
+                    ty.pointer<i32>(builtin::AddressSpace::kStorage, builtin::Access::kReadWrite),
                     AddressOf(expr));
 
     WrapInFunction(ptr);
@@ -359,7 +359,7 @@
 
 TEST_F(ResolverVariableValidationTest, InvalidAddressSpaceForInitializer) {
     // var<workgroup> v : f32 = 1.23;
-    GlobalVar(Source{{12, 34}}, "v", ty.f32(), type::AddressSpace::kWorkgroup, Expr(1.23_f));
+    GlobalVar(Source{{12, 34}}, "v", ty.f32(), builtin::AddressSpace::kWorkgroup, Expr(1.23_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -489,7 +489,7 @@
     // enable chromium_experimental_push_constant;
     // var<push_constant> a : u32 = 0u;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar(Source{{1u, 2u}}, "a", ty.u32(), type::AddressSpace::kPushConstant,
+    GlobalVar(Source{{1u, 2u}}, "a", ty.u32(), builtin::AddressSpace::kPushConstant,
               Expr(Source{{3u, 4u}}, u32(0)));
 
     ASSERT_FALSE(r()->Resolve());
diff --git a/src/tint/sem/builtin.cc b/src/tint/sem/builtin.cc
index 7d13190..8bcd8af 100644
--- a/src/tint/sem/builtin.cc
+++ b/src/tint/sem/builtin.cc
@@ -110,8 +110,9 @@
                  utils::VectorRef<Parameter*> parameters,
                  EvaluationStage eval_stage,
                  PipelineStageSet supported_stages,
-                 bool is_deprecated)
-    : Base(return_type, SetOwner(std::move(parameters), this), eval_stage),
+                 bool is_deprecated,
+                 bool must_use)
+    : Base(return_type, SetOwner(std::move(parameters), this), eval_stage, must_use),
       type_(type),
       supported_stages_(supported_stages),
       is_deprecated_(is_deprecated) {}
diff --git a/src/tint/sem/builtin.h b/src/tint/sem/builtin.h
index 71e5467..55d882e 100644
--- a/src/tint/sem/builtin.h
+++ b/src/tint/sem/builtin.h
@@ -84,16 +84,16 @@
     /// @param return_type the return type for the builtin call
     /// @param parameters the parameters for the builtin overload
     /// @param eval_stage the earliest evaluation stage for a call to the builtin
-    /// @param supported_stages the pipeline stages that this builtin can be
-    /// used in
-    /// @param is_deprecated true if the particular overload is considered
-    /// deprecated
+    /// @param supported_stages the pipeline stages that this builtin can be used in
+    /// @param is_deprecated true if the particular overload is considered deprecated
+    /// @param must_use true if the builtin was annotated with `@must_use`
     Builtin(BuiltinType type,
             const type::Type* return_type,
             utils::VectorRef<Parameter*> parameters,
             EvaluationStage eval_stage,
             PipelineStageSet supported_stages,
-            bool is_deprecated);
+            bool is_deprecated,
+            bool must_use);
 
     /// Destructor
     ~Builtin() override;
diff --git a/src/tint/sem/builtin_type.h b/src/tint/sem/builtin_type.h
index 1328d99..114afb6 100644
--- a/src/tint/sem/builtin_type.h
+++ b/src/tint/sem/builtin_type.h
@@ -161,7 +161,7 @@
 /// matches the name in the WGSL spec.
 std::ostream& operator<<(std::ostream& out, BuiltinType i);
 
-/// All builtin types
+/// All builtin function
 constexpr BuiltinType kBuiltinTypes[] = {
     BuiltinType::kAbs,
     BuiltinType::kAcos,
@@ -279,6 +279,124 @@
     BuiltinType::kTintMaterialize,
 };
 
+/// All builtin function names
+constexpr const char* kBuiltinStrings[] = {
+    "abs",
+    "acos",
+    "acosh",
+    "all",
+    "any",
+    "arrayLength",
+    "asin",
+    "asinh",
+    "atan",
+    "atan2",
+    "atanh",
+    "ceil",
+    "clamp",
+    "cos",
+    "cosh",
+    "countLeadingZeros",
+    "countOneBits",
+    "countTrailingZeros",
+    "cross",
+    "degrees",
+    "determinant",
+    "distance",
+    "dot",
+    "dot4I8Packed",
+    "dot4U8Packed",
+    "dpdx",
+    "dpdxCoarse",
+    "dpdxFine",
+    "dpdy",
+    "dpdyCoarse",
+    "dpdyFine",
+    "exp",
+    "exp2",
+    "extractBits",
+    "faceForward",
+    "firstLeadingBit",
+    "firstTrailingBit",
+    "floor",
+    "fma",
+    "fract",
+    "frexp",
+    "fwidth",
+    "fwidthCoarse",
+    "fwidthFine",
+    "insertBits",
+    "inverseSqrt",
+    "ldexp",
+    "length",
+    "log",
+    "log2",
+    "max",
+    "min",
+    "mix",
+    "modf",
+    "normalize",
+    "pack2x16float",
+    "pack2x16snorm",
+    "pack2x16unorm",
+    "pack4x8snorm",
+    "pack4x8unorm",
+    "pow",
+    "quantizeToF16",
+    "radians",
+    "reflect",
+    "refract",
+    "reverseBits",
+    "round",
+    "saturate",
+    "select",
+    "sign",
+    "sin",
+    "sinh",
+    "smoothstep",
+    "sqrt",
+    "step",
+    "storageBarrier",
+    "tan",
+    "tanh",
+    "transpose",
+    "trunc",
+    "unpack2x16float",
+    "unpack2x16snorm",
+    "unpack2x16unorm",
+    "unpack4x8snorm",
+    "unpack4x8unorm",
+    "workgroupBarrier",
+    "workgroupUniformLoad",
+    "textureDimensions",
+    "textureGather",
+    "textureGatherCompare",
+    "textureNumLayers",
+    "textureNumLevels",
+    "textureNumSamples",
+    "textureSample",
+    "textureSampleBias",
+    "textureSampleCompare",
+    "textureSampleCompareLevel",
+    "textureSampleGrad",
+    "textureSampleLevel",
+    "textureSampleBaseClampToEdge",
+    "textureStore",
+    "textureLoad",
+    "atomicLoad",
+    "atomicStore",
+    "atomicAdd",
+    "atomicSub",
+    "atomicMax",
+    "atomicMin",
+    "atomicAnd",
+    "atomicOr",
+    "atomicXor",
+    "atomicExchange",
+    "atomicCompareExchangeWeak",
+    "_tint_materialize",
+};
+
 }  // namespace tint::sem
 
 #endif  // SRC_TINT_SEM_BUILTIN_TYPE_H_
diff --git a/src/tint/sem/builtin_type.h.tmpl b/src/tint/sem/builtin_type.h.tmpl
index 7cd715b..7e574f5 100644
--- a/src/tint/sem/builtin_type.h.tmpl
+++ b/src/tint/sem/builtin_type.h.tmpl
@@ -41,13 +41,20 @@
 /// matches the name in the WGSL spec.
 std::ostream& operator<<(std::ostream& out, BuiltinType i);
 
-/// All builtin types
+/// All builtin function
 constexpr BuiltinType kBuiltinTypes[] = {
 {{- range Sem.Builtins }}
     BuiltinType::k{{PascalCase .Name}},
 {{- end }}
 };
 
+/// All builtin function names
+constexpr const char* kBuiltinStrings[] = {
+{{- range Sem.Builtins }}
+    "{{.Name}}",
+{{- end }}
+};
+
 }  // namespace tint::sem
 
 #endif  // SRC_TINT_SEM_BUILTIN_TYPE_H_
diff --git a/src/tint/sem/call_target.cc b/src/tint/sem/call_target.cc
index 93fe0f8..76c1ab1 100644
--- a/src/tint/sem/call_target.cc
+++ b/src/tint/sem/call_target.cc
@@ -25,8 +25,9 @@
 
 CallTarget::CallTarget(const type::Type* return_type,
                        utils::VectorRef<const Parameter*> parameters,
-                       EvaluationStage stage)
-    : signature_{return_type, std::move(parameters)}, stage_(stage) {
+                       EvaluationStage stage,
+                       bool must_use)
+    : signature_{return_type, std::move(parameters)}, stage_(stage), must_use_(must_use) {
     TINT_ASSERT(Semantic, return_type);
 }
 
diff --git a/src/tint/sem/call_target.h b/src/tint/sem/call_target.h
index fed8a82..4f0ab33 100644
--- a/src/tint/sem/call_target.h
+++ b/src/tint/sem/call_target.h
@@ -62,17 +62,20 @@
     }
 };
 
-/// CallTarget is the base for callable functions, builtins, type initializers
-/// and type casts.
+/// CallTarget is the base for callable functions, builtins, value constructors and value
+/// conversions.
 class CallTarget : public Castable<CallTarget, Node> {
   public:
     /// Constructor
-    /// @param stage the earliest evaluation stage for a call to this target
     /// @param return_type the return type of the call target
     /// @param parameters the parameters for the call target
+    /// @param stage the earliest evaluation stage for a call to this target
+    /// @param must_use the result of the call target must be used, i.e. it cannot be used as a call
+    /// statement.
     CallTarget(const type::Type* return_type,
                utils::VectorRef<const Parameter*> parameters,
-               EvaluationStage stage);
+               EvaluationStage stage,
+               bool must_use);
 
     /// Copy constructor
     CallTarget(const CallTarget&);
@@ -92,9 +95,14 @@
     /// @return the earliest evaluation stage for a call to this target
     EvaluationStage Stage() const { return stage_; }
 
+    /// @returns true if the result of the call target must be used, i.e. it cannot be used as a
+    /// call statement.
+    bool MustUse() const { return must_use_; }
+
   private:
     CallTargetSignature signature_;
     EvaluationStage stage_;
+    const bool must_use_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/diagnostic_severity_test.cc b/src/tint/sem/diagnostic_severity_test.cc
index f91277b..fa57b55 100644
--- a/src/tint/sem/diagnostic_severity_test.cc
+++ b/src/tint/sem/diagnostic_severity_test.cc
@@ -27,7 +27,7 @@
     /// using an attribute. Test that we correctly track the severity of the filter for the
     /// functions and the statements with them.
     /// @param global_severity the global severity of the "chromium_unreachable_code" filter
-    void Run(ast::DiagnosticSeverity global_severity) {
+    void Run(builtin::DiagnosticSeverity global_severity) {
         // @diagnostic(off, chromium_unreachable_code)
         // fn foo() {
         //   @diagnostic(info, chromium_unreachable_code) {
@@ -44,10 +44,10 @@
         //     }
         //   }
         // }
-        auto rule = ast::DiagnosticRule::kChromiumUnreachableCode;
-        auto func_severity = ast::DiagnosticSeverity::kOff;
-        auto block_severity = ast::DiagnosticSeverity::kInfo;
-        auto if_severity = ast::DiagnosticSeverity::kInfo;
+        auto rule = builtin::DiagnosticRule::kChromiumUnreachableCode;
+        auto func_severity = builtin::DiagnosticSeverity::kOff;
+        auto block_severity = builtin::DiagnosticSeverity::kInfo;
+        auto if_severity = builtin::DiagnosticSeverity::kInfo;
         auto attr = [&](auto severity) {
             return utils::Vector{DiagnosticAttribute(severity, "chromium_unreachable_code")};
         };
@@ -74,12 +74,12 @@
 };
 
 TEST_F(DiagnosticSeverityTest, WithDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
-    Run(ast::DiagnosticSeverity::kError);
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
+    Run(builtin::DiagnosticSeverity::kError);
 }
 
 TEST_F(DiagnosticSeverityTest, WithoutDirective) {
-    Run(ast::DiagnosticSeverity::kWarning);
+    Run(builtin::DiagnosticSeverity::kWarning);
 }
 
 }  // namespace
diff --git a/src/tint/sem/function.cc b/src/tint/sem/function.cc
index e7bf889..0859dd8 100644
--- a/src/tint/sem/function.cc
+++ b/src/tint/sem/function.cc
@@ -16,6 +16,7 @@
 
 #include "src/tint/ast/function.h"
 #include "src/tint/ast/identifier.h"
+#include "src/tint/ast/must_use_attribute.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/type/depth_texture.h"
 #include "src/tint/type/external_texture.h"
@@ -43,7 +44,10 @@
                    type::Type* return_type,
                    std::optional<uint32_t> return_location,
                    utils::VectorRef<Parameter*> parameters)
-    : Base(return_type, SetOwner(std::move(parameters), this), EvaluationStage::kRuntime),
+    : Base(return_type,
+           SetOwner(std::move(parameters), this),
+           EvaluationStage::kRuntime,
+           ast::HasAttribute<ast::MustUseAttribute>(declaration->attributes)),
       declaration_(declaration),
       workgroup_size_{1, 1, 1},
       return_location_(return_location) {}
@@ -69,7 +73,7 @@
     VariableBindings ret;
 
     for (auto* global : TransitivelyReferencedGlobals()) {
-        if (global->AddressSpace() != type::AddressSpace::kUniform) {
+        if (global->AddressSpace() != builtin::AddressSpace::kUniform) {
             continue;
         }
 
@@ -84,7 +88,7 @@
     VariableBindings ret;
 
     for (auto* global : TransitivelyReferencedGlobals()) {
-        if (global->AddressSpace() != type::AddressSpace::kStorage) {
+        if (global->AddressSpace() != builtin::AddressSpace::kStorage) {
             continue;
         }
 
diff --git a/src/tint/sem/function.h b/src/tint/sem/function.h
index 25bacda..528ebef 100644
--- a/src/tint/sem/function.h
+++ b/src/tint/sem/function.h
@@ -260,12 +260,12 @@
     /// Modifies the severity of a specific diagnostic rule for this function.
     /// @param rule the diagnostic rule
     /// @param severity the new diagnostic severity
-    void SetDiagnosticSeverity(ast::DiagnosticRule rule, ast::DiagnosticSeverity severity) {
+    void SetDiagnosticSeverity(builtin::DiagnosticRule rule, builtin::DiagnosticSeverity severity) {
         diagnostic_severities_[rule] = severity;
     }
 
     /// @returns the diagnostic severity modifications applied to this function
-    const ast::DiagnosticRuleSeverities& DiagnosticSeverities() const {
+    const builtin::DiagnosticRuleSeverities& DiagnosticSeverities() const {
         return diagnostic_severities_;
     }
 
@@ -289,7 +289,7 @@
     std::vector<const Function*> ancestor_entry_points_;
     const Statement* discard_stmt_ = nullptr;
     sem::Behaviors behaviors_{sem::Behavior::kNext};
-    ast::DiagnosticRuleSeverities diagnostic_severities_;
+    builtin::DiagnosticRuleSeverities diagnostic_severities_;
 
     std::optional<uint32_t> return_location_;
 };
diff --git a/src/tint/sem/info.cc b/src/tint/sem/info.cc
index a6a563e..e124c1c 100644
--- a/src/tint/sem/info.cc
+++ b/src/tint/sem/info.cc
@@ -29,8 +29,8 @@
 
 Info& Info::operator=(Info&&) = default;
 
-ast::DiagnosticSeverity Info::DiagnosticSeverity(const ast::Node* ast_node,
-                                                 ast::DiagnosticRule rule) const {
+builtin::DiagnosticSeverity Info::DiagnosticSeverity(const ast::Node* ast_node,
+                                                     builtin::DiagnosticRule rule) const {
     // Get the diagnostic severity modification for a node.
     auto check = [&](auto* node) {
         auto& severities = node->DiagnosticSeverities();
@@ -38,13 +38,13 @@
         if (itr != severities.end()) {
             return itr->second;
         }
-        return ast::DiagnosticSeverity::kUndefined;
+        return builtin::DiagnosticSeverity::kUndefined;
     };
 
     // Get the diagnostic severity modification for a function.
     auto check_func = [&](const sem::Function* func) {
         auto severity = check(func);
-        if (severity != ast::DiagnosticSeverity::kUndefined) {
+        if (severity != builtin::DiagnosticSeverity::kUndefined) {
             return severity;
         }
 
@@ -57,7 +57,7 @@
         // Walk up the statement hierarchy, checking for diagnostic severity modifications.
         while (true) {
             auto severity = check(stmt);
-            if (severity != ast::DiagnosticSeverity::kUndefined) {
+            if (severity != builtin::DiagnosticSeverity::kUndefined) {
                 return severity;
             }
             if (!stmt->Parent()) {
@@ -82,7 +82,7 @@
             // Use the global severity set on the module.
             return check(module_);
         });
-    TINT_ASSERT(Resolver, severity != ast::DiagnosticSeverity::kUndefined);
+    TINT_ASSERT(Resolver, severity != builtin::DiagnosticSeverity::kUndefined);
     return severity;
 }
 
diff --git a/src/tint/sem/info.h b/src/tint/sem/info.h
index 2ce46f5..29b3bc4 100644
--- a/src/tint/sem/info.h
+++ b/src/tint/sem/info.h
@@ -161,8 +161,8 @@
     /// @param ast_node the AST node
     /// @param rule the diagnostic rule
     /// @returns the severity of the rule for that AST node
-    ast::DiagnosticSeverity DiagnosticSeverity(const ast::Node* ast_node,
-                                               ast::DiagnosticRule rule) const;
+    builtin::DiagnosticSeverity DiagnosticSeverity(const ast::Node* ast_node,
+                                                   builtin::DiagnosticRule rule) const;
 
   private:
     // AST node index to semantic node
diff --git a/src/tint/sem/module.h b/src/tint/sem/module.h
index 6bcd802..ba4e0a9 100644
--- a/src/tint/sem/module.h
+++ b/src/tint/sem/module.h
@@ -50,19 +50,19 @@
     /// Modifies the severity of a specific diagnostic rule for this module.
     /// @param rule the diagnostic rule
     /// @param severity the new diagnostic severity
-    void SetDiagnosticSeverity(ast::DiagnosticRule rule, ast::DiagnosticSeverity severity) {
+    void SetDiagnosticSeverity(builtin::DiagnosticRule rule, builtin::DiagnosticSeverity severity) {
         diagnostic_severities_[rule] = severity;
     }
 
     /// @returns the diagnostic severity modifications applied to this module
-    const ast::DiagnosticRuleSeverities& DiagnosticSeverities() const {
+    const builtin::DiagnosticRuleSeverities& DiagnosticSeverities() const {
         return diagnostic_severities_;
     }
 
   private:
     const utils::Vector<const ast::Node*, 64> dep_ordered_decls_;
     builtin::Extensions extensions_;
-    ast::DiagnosticRuleSeverities diagnostic_severities_;
+    builtin::DiagnosticRuleSeverities diagnostic_severities_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/statement.h b/src/tint/sem/statement.h
index 2d17295..373b9f6 100644
--- a/src/tint/sem/statement.h
+++ b/src/tint/sem/statement.h
@@ -113,12 +113,12 @@
     /// Modifies the severity of a specific diagnostic rule for this statement.
     /// @param rule the diagnostic rule
     /// @param severity the new diagnostic severity
-    void SetDiagnosticSeverity(ast::DiagnosticRule rule, ast::DiagnosticSeverity severity) {
+    void SetDiagnosticSeverity(builtin::DiagnosticRule rule, builtin::DiagnosticSeverity severity) {
         diagnostic_severities_[rule] = severity;
     }
 
     /// @returns the diagnostic severity modifications applied to this statement
-    const ast::DiagnosticRuleSeverities& DiagnosticSeverities() const {
+    const builtin::DiagnosticRuleSeverities& DiagnosticSeverities() const {
         return diagnostic_severities_;
     }
 
@@ -128,7 +128,7 @@
     const sem::Function* const function_;
     sem::Behaviors behaviors_{sem::Behavior::kNext};
     bool is_reachable_ = true;
-    ast::DiagnosticRuleSeverities diagnostic_severities_;
+    builtin::DiagnosticRuleSeverities diagnostic_severities_;
 };
 
 /// CompoundStatement is the base class of statements that can hold other
diff --git a/src/tint/sem/struct.h b/src/tint/sem/struct.h
index 42a1117..d1d20cc 100644
--- a/src/tint/sem/struct.h
+++ b/src/tint/sem/struct.h
@@ -18,8 +18,8 @@
 #include <optional>
 
 #include "src/tint/ast/struct.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/symbol.h"
-#include "src/tint/type/address_space.h"
 #include "src/tint/type/struct.h"
 #include "src/tint/type/type.h"
 #include "src/tint/utils/vector.h"
diff --git a/src/tint/sem/type_mappings.h b/src/tint/sem/type_mappings.h
index fa7d8c6..efcd3a6 100644
--- a/src/tint/sem/type_mappings.h
+++ b/src/tint/sem/type_mappings.h
@@ -17,6 +17,8 @@
 
 #include <type_traits>
 
+#include "src/tint/sem/builtin_enum_expression.h"
+
 // Forward declarations
 namespace tint {
 class CastableBase;
@@ -25,6 +27,7 @@
 class AccessorExpression;
 class BinaryExpression;
 class BitcastExpression;
+class BuiltinAttribute;
 class CallExpression;
 class Expression;
 class ForLoopStatement;
@@ -43,6 +46,9 @@
 class WhileStatement;
 class UnaryOpExpression;
 }  // namespace tint::ast
+namespace tint::builtin {
+enum class BuiltinValue;
+}
 namespace tint::sem {
 class Expression;
 class ForLoopStatement;
@@ -71,21 +77,22 @@
 /// rules will be used to infer the return type based on the argument type.
 struct TypeMappings {
     //! @cond Doxygen_Suppress
+    BuiltinEnumExpression<builtin::BuiltinValue>* operator()(ast::BuiltinAttribute*);
+    CastableBase* operator()(ast::Node*);
+    Expression* operator()(ast::Expression*);
     ForLoopStatement* operator()(ast::ForLoopStatement*);
     Function* operator()(ast::Function*);
-    IfStatement* operator()(ast::IfStatement*);
-    CastableBase* operator()(ast::Node*);
     GlobalVariable* operator()(ast::Override*);
+    IfStatement* operator()(ast::IfStatement*);
     Statement* operator()(ast::Statement*);
     Struct* operator()(ast::Struct*);
     StructMember* operator()(ast::StructMember*);
     SwitchStatement* operator()(ast::SwitchStatement*);
     type::Type* operator()(ast::TypeDecl*);
-    Expression* operator()(ast::Expression*);
     ValueExpression* operator()(ast::AccessorExpression*);
-    ValueExpression* operator()(ast::CallExpression*);
     ValueExpression* operator()(ast::BinaryExpression*);
     ValueExpression* operator()(ast::BitcastExpression*);
+    ValueExpression* operator()(ast::CallExpression*);
     ValueExpression* operator()(ast::LiteralExpression*);
     ValueExpression* operator()(ast::PhonyExpression*);
     ValueExpression* operator()(ast::UnaryOpExpression*);
diff --git a/src/tint/sem/type_initializer.cc b/src/tint/sem/value_constructor.cc
similarity index 61%
rename from src/tint/sem/type_initializer.cc
rename to src/tint/sem/value_constructor.cc
index 0359eb8..62be478 100644
--- a/src/tint/sem/type_initializer.cc
+++ b/src/tint/sem/value_constructor.cc
@@ -12,19 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
 
 #include <utility>
 
-TINT_INSTANTIATE_TYPEINFO(tint::sem::TypeInitializer);
+TINT_INSTANTIATE_TYPEINFO(tint::sem::ValueConstructor);
 
 namespace tint::sem {
 
-TypeInitializer::TypeInitializer(const type::Type* type,
-                                 utils::VectorRef<const Parameter*> parameters,
-                                 EvaluationStage stage)
-    : Base(type, std::move(parameters), stage) {}
+ValueConstructor::ValueConstructor(const type::Type* type,
+                                   utils::VectorRef<const Parameter*> parameters,
+                                   EvaluationStage stage)
+    : Base(type, std::move(parameters), stage, /* must_use */ true) {}
 
-TypeInitializer::~TypeInitializer() = default;
+ValueConstructor::~ValueConstructor() = default;
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/type_initializer.h b/src/tint/sem/value_constructor.h
similarity index 63%
rename from src/tint/sem/type_initializer.h
rename to src/tint/sem/value_constructor.h
index b46faa8..aef827b 100644
--- a/src/tint/sem/type_initializer.h
+++ b/src/tint/sem/value_constructor.h
@@ -12,29 +12,29 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_SEM_TYPE_INITIALIZER_H_
-#define SRC_TINT_SEM_TYPE_INITIALIZER_H_
+#ifndef SRC_TINT_SEM_VALUE_CONSTRUCTOR_H_
+#define SRC_TINT_SEM_VALUE_CONSTRUCTOR_H_
 
 #include "src/tint/sem/call_target.h"
 #include "src/tint/utils/vector.h"
 
 namespace tint::sem {
 
-/// TypeInitializer is the CallTarget for a type initializer.
-class TypeInitializer final : public Castable<TypeInitializer, CallTarget> {
+/// ValueConstructor is the CallTarget for a value constructor.
+class ValueConstructor final : public Castable<ValueConstructor, CallTarget> {
   public:
     /// Constructor
     /// @param type the type that's being constructed
-    /// @param parameters the type initializer parameters
+    /// @param parameters the constructor parameters
     /// @param stage the earliest evaluation stage for the expression
-    TypeInitializer(const type::Type* type,
-                    utils::VectorRef<const Parameter*> parameters,
-                    EvaluationStage stage);
+    ValueConstructor(const type::Type* type,
+                     utils::VectorRef<const Parameter*> parameters,
+                     EvaluationStage stage);
 
     /// Destructor
-    ~TypeInitializer() override;
+    ~ValueConstructor() override;
 };
 
 }  // namespace tint::sem
 
-#endif  // SRC_TINT_SEM_TYPE_INITIALIZER_H_
+#endif  // SRC_TINT_SEM_VALUE_CONSTRUCTOR_H_
diff --git a/src/tint/sem/type_conversion.cc b/src/tint/sem/value_conversion.cc
similarity index 66%
rename from src/tint/sem/type_conversion.cc
rename to src/tint/sem/value_conversion.cc
index 2cec5be..37331af 100644
--- a/src/tint/sem/type_conversion.cc
+++ b/src/tint/sem/value_conversion.cc
@@ -12,17 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/type_conversion.h"
+#include "src/tint/sem/value_conversion.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::sem::TypeConversion);
+TINT_INSTANTIATE_TYPEINFO(tint::sem::ValueConversion);
 
 namespace tint::sem {
 
-TypeConversion::TypeConversion(const type::Type* type,
-                               const sem::Parameter* parameter,
-                               EvaluationStage stage)
-    : Base(type, utils::Vector<const sem::Parameter*, 1>{parameter}, stage) {}
+ValueConversion::ValueConversion(const type::Type* type,
+                                 const sem::Parameter* parameter,
+                                 EvaluationStage stage)
+    : Base(type, utils::Vector<const sem::Parameter*, 1>{parameter}, stage, /* must_use */ true) {}
 
-TypeConversion::~TypeConversion() = default;
+ValueConversion::~ValueConversion() = default;
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/type_conversion.h b/src/tint/sem/value_conversion.h
similarity index 73%
rename from src/tint/sem/type_conversion.h
rename to src/tint/sem/value_conversion.h
index c489127..b79caa3 100644
--- a/src/tint/sem/type_conversion.h
+++ b/src/tint/sem/value_conversion.h
@@ -12,24 +12,24 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_SEM_TYPE_CONVERSION_H_
-#define SRC_TINT_SEM_TYPE_CONVERSION_H_
+#ifndef SRC_TINT_SEM_VALUE_CONVERSION_H_
+#define SRC_TINT_SEM_VALUE_CONVERSION_H_
 
 #include "src/tint/sem/call_target.h"
 
 namespace tint::sem {
 
-/// TypeConversion is the CallTarget for a type conversion (cast).
-class TypeConversion final : public Castable<TypeConversion, CallTarget> {
+/// ValueConversion is the CallTarget for a value conversion (cast).
+class ValueConversion final : public Castable<ValueConversion, CallTarget> {
   public:
     /// Constructor
     /// @param type the target type of the cast
     /// @param parameter the type cast parameter
     /// @param stage the earliest evaluation stage for the expression
-    TypeConversion(const type::Type* type, const sem::Parameter* parameter, EvaluationStage stage);
+    ValueConversion(const type::Type* type, const sem::Parameter* parameter, EvaluationStage stage);
 
     /// Destructor
-    ~TypeConversion() override;
+    ~ValueConversion() override;
 
     /// @returns the cast source type
     const type::Type* Source() const { return Parameters()[0]->Type(); }
@@ -40,4 +40,4 @@
 
 }  // namespace tint::sem
 
-#endif  // SRC_TINT_SEM_TYPE_CONVERSION_H_
+#endif  // SRC_TINT_SEM_VALUE_CONVERSION_H_
diff --git a/src/tint/sem/variable.cc b/src/tint/sem/variable.cc
index 6dc327d..8f8248c 100644
--- a/src/tint/sem/variable.cc
+++ b/src/tint/sem/variable.cc
@@ -31,8 +31,8 @@
 Variable::Variable(const ast::Variable* declaration,
                    const type::Type* type,
                    EvaluationStage stage,
-                   type::AddressSpace address_space,
-                   type::Access access,
+                   builtin::AddressSpace address_space,
+                   builtin::Access access,
                    const constant::Value* constant_value)
     : declaration_(declaration),
       type_(type),
@@ -46,8 +46,8 @@
 LocalVariable::LocalVariable(const ast::Variable* declaration,
                              const type::Type* type,
                              EvaluationStage stage,
-                             type::AddressSpace address_space,
-                             type::Access access,
+                             builtin::AddressSpace address_space,
+                             builtin::Access access,
                              const sem::Statement* statement,
                              const constant::Value* constant_value)
     : Base(declaration, type, stage, address_space, access, constant_value),
@@ -58,8 +58,8 @@
 GlobalVariable::GlobalVariable(const ast::Variable* declaration,
                                const type::Type* type,
                                EvaluationStage stage,
-                               type::AddressSpace address_space,
-                               type::Access access,
+                               builtin::AddressSpace address_space,
+                               builtin::Access access,
                                const constant::Value* constant_value,
                                sem::BindingPoint binding_point,
                                std::optional<uint32_t> location)
@@ -72,8 +72,8 @@
 Parameter::Parameter(const ast::Parameter* declaration,
                      uint32_t index,
                      const type::Type* type,
-                     type::AddressSpace address_space,
-                     type::Access access,
+                     builtin::AddressSpace address_space,
+                     builtin::Access access,
                      const ParameterUsage usage /* = ParameterUsage::kNone */,
                      sem::BindingPoint binding_point /* = {} */,
                      std::optional<uint32_t> location /* = std::nullopt */)
diff --git a/src/tint/sem/variable.h b/src/tint/sem/variable.h
index afaa0d1..701a3f1 100644
--- a/src/tint/sem/variable.h
+++ b/src/tint/sem/variable.h
@@ -22,11 +22,11 @@
 #include "tint/override_id.h"
 
 #include "src/tint/ast/parameter.h"
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/sem/binding_point.h"
 #include "src/tint/sem/parameter_usage.h"
 #include "src/tint/sem/value_expression.h"
-#include "src/tint/type/access.h"
-#include "src/tint/type/address_space.h"
 #include "src/tint/type/type.h"
 #include "src/tint/utils/unique_vector.h"
 
@@ -57,8 +57,8 @@
     Variable(const ast::Variable* declaration,
              const type::Type* type,
              EvaluationStage stage,
-             type::AddressSpace address_space,
-             type::Access access,
+             builtin::AddressSpace address_space,
+             builtin::Access access,
              const constant::Value* constant_value);
 
     /// Destructor
@@ -74,10 +74,10 @@
     EvaluationStage Stage() const { return stage_; }
 
     /// @returns the address space for the variable
-    type::AddressSpace AddressSpace() const { return address_space_; }
+    builtin::AddressSpace AddressSpace() const { return address_space_; }
 
     /// @returns the access control for the variable
-    type::Access Access() const { return access_; }
+    builtin::Access Access() const { return access_; }
 
     /// @return the constant value of this expression
     const constant::Value* ConstantValue() const { return constant_value_; }
@@ -100,8 +100,8 @@
     const ast::Variable* const declaration_;
     const type::Type* const type_;
     const EvaluationStage stage_;
-    const type::AddressSpace address_space_;
-    const type::Access access_;
+    const builtin::AddressSpace address_space_;
+    const builtin::Access access_;
     const constant::Value* constant_value_;
     const ValueExpression* initializer_ = nullptr;
     std::vector<const VariableUser*> users_;
@@ -121,8 +121,8 @@
     LocalVariable(const ast::Variable* declaration,
                   const type::Type* type,
                   EvaluationStage stage,
-                  type::AddressSpace address_space,
-                  type::Access access,
+                  builtin::AddressSpace address_space,
+                  builtin::Access access,
                   const sem::Statement* statement,
                   const constant::Value* constant_value);
 
@@ -162,8 +162,8 @@
     GlobalVariable(const ast::Variable* declaration,
                    const type::Type* type,
                    EvaluationStage stage,
-                   type::AddressSpace address_space,
-                   type::Access access,
+                   builtin::AddressSpace address_space,
+                   builtin::Access access,
                    const constant::Value* constant_value,
                    sem::BindingPoint binding_point = {},
                    std::optional<uint32_t> location = std::nullopt);
@@ -205,8 +205,8 @@
     Parameter(const ast::Parameter* declaration,
               uint32_t index,
               const type::Type* type,
-              type::AddressSpace address_space,
-              type::Access access,
+              builtin::AddressSpace address_space,
+              builtin::Access access,
               const ParameterUsage usage = ParameterUsage::kNone,
               sem::BindingPoint binding_point = {},
               std::optional<uint32_t> location = std::nullopt);
diff --git a/src/tint/symbol_table.cc b/src/tint/symbol_table.cc
index 2b20fed..4f21d0b 100644
--- a/src/tint/symbol_table.cc
+++ b/src/tint/symbol_table.cc
@@ -33,9 +33,9 @@
 Symbol SymbolTable::Register(const std::string& name) {
     TINT_ASSERT(Symbol, !name.empty());
 
-    auto it = name_to_symbol_.find(name);
-    if (it != name_to_symbol_.end()) {
-        return it->second;
+    auto it = name_to_symbol_.Find(name);
+    if (it) {
+        return *it;
     }
 
 #if TINT_SYMBOL_STORE_DEBUG_NAME
@@ -45,40 +45,54 @@
 #endif
     ++next_symbol_;
 
-    name_to_symbol_[name] = sym;
-    symbol_to_name_[sym] = name;
+    name_to_symbol_.Add(name, sym);
+    symbol_to_name_.Add(sym, name);
 
     return sym;
 }
 
 Symbol SymbolTable::Get(const std::string& name) const {
-    auto it = name_to_symbol_.find(name);
-    return it != name_to_symbol_.end() ? it->second : Symbol();
+    auto it = name_to_symbol_.Find(name);
+    return it ? *it : Symbol();
 }
 
 std::string SymbolTable::NameFor(const Symbol symbol) const {
     TINT_ASSERT_PROGRAM_IDS_EQUAL(Symbol, program_id_, symbol);
-    auto it = symbol_to_name_.find(symbol);
-    if (it == symbol_to_name_.end()) {
+    auto it = symbol_to_name_.Find(symbol);
+    if (!it) {
         return symbol.to_str();
     }
 
-    return it->second;
+    return *it;
 }
 
 Symbol SymbolTable::New(std::string prefix /* = "" */) {
     if (prefix.empty()) {
         prefix = "tint_symbol";
     }
-    auto it = name_to_symbol_.find(prefix);
-    if (it == name_to_symbol_.end()) {
+    auto it = name_to_symbol_.Find(prefix);
+    if (!it) {
         return Register(prefix);
     }
+
+    size_t i = 0;
+    auto last_prefix = last_prefix_to_index_.Find(prefix);
+    if (last_prefix) {
+        i = *last_prefix;
+    }
+
     std::string name;
-    size_t i = 1;
     do {
-        name = prefix + "_" + std::to_string(i++);
-    } while (name_to_symbol_.count(name));
+        ++i;
+        name = prefix + "_" + std::to_string(i);
+    } while (name_to_symbol_.Contains(name));
+
+    if (last_prefix) {
+        *last_prefix = i;
+    } else {
+        last_prefix_to_index_.Add(prefix, i);
+    }
+
     return Register(name);
 }
 
diff --git a/src/tint/symbol_table.h b/src/tint/symbol_table.h
index 4881c2d..937a764 100644
--- a/src/tint/symbol_table.h
+++ b/src/tint/symbol_table.h
@@ -16,7 +16,7 @@
 #define SRC_TINT_SYMBOL_TABLE_H_
 
 #include <string>
-#include <unordered_map>
+#include "utils/hashmap.h"
 
 #include "src/tint/symbol.h"
 
@@ -74,7 +74,7 @@
     template <typename F>
     void Foreach(F&& callback) const {
         for (auto it : symbol_to_name_) {
-            callback(it.first, it.second);
+            callback(it.key, it.value);
         }
     }
 
@@ -85,8 +85,9 @@
     // The value to be associated to the next registered symbol table entry.
     uint32_t next_symbol_ = 1;
 
-    std::unordered_map<Symbol, std::string> symbol_to_name_;
-    std::unordered_map<std::string, Symbol> name_to_symbol_;
+    utils::Hashmap<Symbol, std::string, 0> symbol_to_name_;
+    utils::Hashmap<std::string, Symbol, 0> name_to_symbol_;
+    utils::Hashmap<std::string, size_t, 0> last_prefix_to_index_;
     tint::ProgramID program_id_;
 };
 
diff --git a/src/tint/transform/add_block_attribute.cc b/src/tint/transform/add_block_attribute.cc
index 2b1ec31..c63bd04 100644
--- a/src/tint/transform/add_block_attribute.cc
+++ b/src/tint/transform/add_block_attribute.cc
@@ -47,7 +47,7 @@
     bool made_changes = false;
     for (auto* global : src->AST().GlobalVariables()) {
         auto* var = sem.Get(global);
-        if (!type::IsHostShareable(var->AddressSpace())) {
+        if (!builtin::IsHostShareable(var->AddressSpace())) {
             // Not declared in a host-sharable address space
             continue;
         }
diff --git a/src/tint/transform/add_block_attribute_test.cc b/src/tint/transform/add_block_attribute_test.cc
index 74dd5a9..4a02db9 100644
--- a/src/tint/transform/add_block_attribute_test.cc
+++ b/src/tint/transform/add_block_attribute_test.cc
@@ -132,7 +132,7 @@
 
 TEST_F(AddBlockAttributeTest, BasicArray_Alias) {
     auto* src = R"(
-type Numbers = array<vec4<f32>, 4u>;
+alias Numbers = array<vec4<f32>, 4u>;
 
 @group(0) @binding(0)
 var<uniform> u : Numbers;
@@ -693,13 +693,13 @@
   f : f32,
 };
 
-type MyInner = Inner;
+alias MyInner = Inner;
 
 struct Outer {
   i : MyInner,
 };
 
-type MyOuter = Outer;
+alias MyOuter = Outer;
 
 @group(0) @binding(0)
 var<uniform> u0 : MyOuter;
@@ -763,12 +763,12 @@
 @group(0) @binding(1)
 var<uniform> u1 : MyInner;
 
-type MyInner = Inner;
+alias MyInner = Inner;
 
 @group(0) @binding(0)
 var<uniform> u0 : MyOuter;
 
-type MyOuter = Outer;
+alias MyOuter = Outer;
 
 struct Outer {
   i : MyInner,
diff --git a/src/tint/transform/array_length_from_uniform.cc b/src/tint/transform/array_length_from_uniform.cc
index 444a328..78535f1 100644
--- a/src/tint/transform/array_length_from_uniform.cc
+++ b/src/tint/transform/array_length_from_uniform.cc
@@ -106,10 +106,10 @@
                                           b.ty.array(b.ty.vec4(b.ty.u32()),
                                                      u32((max_buffer_size_index / 4) + 1))),
                              });
-                buffer_size_ubo =
-                    b.GlobalVar(b.Sym(), b.ty.Of(buffer_size_struct), type::AddressSpace::kUniform,
-                                b.Group(AInt(cfg->ubo_binding.group)),
-                                b.Binding(AInt(cfg->ubo_binding.binding)));
+                buffer_size_ubo = b.GlobalVar(b.Sym(), b.ty.Of(buffer_size_struct),
+                                              builtin::AddressSpace::kUniform,
+                                              b.Group(AInt(cfg->ubo_binding.group)),
+                                              b.Binding(AInt(cfg->ubo_binding.binding)));
             }
             return buffer_size_ubo;
         };
diff --git a/src/tint/transform/array_length_from_uniform_test.cc b/src/tint/transform/array_length_from_uniform_test.cc
index b5d9e77..4525cbc 100644
--- a/src/tint/transform/array_length_from_uniform_test.cc
+++ b/src/tint/transform/array_length_from_uniform_test.cc
@@ -514,43 +514,5 @@
               got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
 }
 
-TEST_F(ArrayLengthFromUniformTest, CallStatement) {
-    auto* src = R"(
-struct SB {
-  arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> a : SB;
-
-@compute @workgroup_size(1)
-fn main() {
-  arrayLength(&a.arr);
-}
-)";
-
-    auto* expect =
-        R"(
-struct SB {
-  arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> a : SB;
-
-@compute @workgroup_size(1)
-fn main() {
-}
-)";
-
-    ArrayLengthFromUniform::Config cfg({0, 30u});
-    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
-
-    DataMap data;
-    data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
-
-    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
-
-    EXPECT_EQ(expect, str(got));
-}
-
 }  // namespace
 }  // namespace tint::transform
diff --git a/src/tint/transform/binding_remapper.cc b/src/tint/transform/binding_remapper.cc
index b657980..ecbd5cd 100644
--- a/src/tint/transform/binding_remapper.cc
+++ b/src/tint/transform/binding_remapper.cc
@@ -122,15 +122,16 @@
             // Replace any access controls.
             auto ac_it = remappings->access_controls.find(from);
             if (ac_it != remappings->access_controls.end()) {
-                type::Access ac = ac_it->second;
-                if (ac == type::Access::kUndefined) {
-                    b.Diagnostics().add_error(
-                        diag::System::Transform,
-                        "invalid access mode (" + std::to_string(static_cast<uint32_t>(ac)) + ")");
+                builtin::Access access = ac_it->second;
+                if (access == builtin::Access::kUndefined) {
+                    b.Diagnostics().add_error(diag::System::Transform,
+                                              "invalid access mode (" +
+                                                  std::to_string(static_cast<uint32_t>(access)) +
+                                                  ")");
                     return Program(std::move(b));
                 }
                 auto* sem = src->Sem().Get(var);
-                if (sem->AddressSpace() != type::AddressSpace::kStorage) {
+                if (sem->AddressSpace() != builtin::AddressSpace::kStorage) {
                     b.Diagnostics().add_error(
                         diag::System::Transform,
                         "cannot apply access control to variable with address space " +
@@ -139,9 +140,14 @@
                 }
                 auto* ty = sem->Type()->UnwrapRef();
                 auto inner_ty = CreateASTTypeFor(ctx, ty);
-                auto* new_var = b.Var(ctx.Clone(var->source), ctx.Clone(var->name->symbol),
-                                      inner_ty, var->declared_address_space, ac,
-                                      ctx.Clone(var->initializer), ctx.Clone(var->attributes));
+                auto* new_var =
+                    b.create<ast::Var>(ctx.Clone(var->source),                  // source
+                                       b.Ident(ctx.Clone(var->name->symbol)),   // name
+                                       inner_ty,                                // type
+                                       ctx.Clone(var->declared_address_space),  // address space
+                                       b.Expr(access),                          // access
+                                       ctx.Clone(var->initializer),             // initializer
+                                       ctx.Clone(var->attributes));             // attributes
                 ctx.Replace(var, new_var);
             }
 
diff --git a/src/tint/transform/binding_remapper.h b/src/tint/transform/binding_remapper.h
index e0f48b3..8fdba2a 100644
--- a/src/tint/transform/binding_remapper.h
+++ b/src/tint/transform/binding_remapper.h
@@ -17,9 +17,9 @@
 
 #include <unordered_map>
 
+#include "src/tint/builtin/access.h"
 #include "src/tint/sem/binding_point.h"
 #include "src/tint/transform/transform.h"
-#include "src/tint/type/access.h"
 
 namespace tint::transform {
 
@@ -34,7 +34,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, type::Access>;
+    using AccessControls = std::unordered_map<BindingPoint, builtin::Access>;
 
     /// Remappings is consumed by the BindingRemapper transform.
     /// Data holds information about shader usage and constant buffer offsets.
diff --git a/src/tint/transform/binding_remapper_test.cc b/src/tint/transform/binding_remapper_test.cc
index 5bed528..b4b7b29 100644
--- a/src/tint/transform/binding_remapper_test.cc
+++ b/src/tint/transform/binding_remapper_test.cc
@@ -52,7 +52,7 @@
     DataMap data;
     data.Add<BindingRemapper::Remappings>(BindingRemapper::BindingPoints{},
                                           BindingRemapper::AccessControls{
-                                              {{2, 1}, type::Access::kWrite},
+                                              {{2, 1}, builtin::Access::kWrite},
                                           });
 
     EXPECT_TRUE(ShouldRun<BindingRemapper>(src, data));
@@ -162,9 +162,9 @@
     data.Add<BindingRemapper::Remappings>(
         BindingRemapper::BindingPoints{},
         BindingRemapper::AccessControls{
-            {{2, 1}, type::Access::kReadWrite},  // Modify access control
+            {{2, 1}, builtin::Access::kReadWrite},  // Modify access control
             // Keep @group(3) @binding(2) as is
-            {{4, 3}, type::Access::kRead},  // Add access control
+            {{4, 3}, builtin::Access::kRead},  // Add access control
         });
     auto got = Run<BindingRemapper>(src, data);
 
@@ -207,8 +207,8 @@
             {{3, 2}, {6, 7}},
         },
         BindingRemapper::AccessControls{
-            {{2, 1}, type::Access::kReadWrite},
-            {{3, 2}, type::Access::kReadWrite},
+            {{2, 1}, builtin::Access::kReadWrite},
+            {{3, 2}, builtin::Access::kReadWrite},
         });
     auto got = Run<BindingRemapper>(src, data);
 
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc
index 917d418..606c6ce 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/transform/builtin_polyfill.cc
@@ -679,7 +679,7 @@
         auto name = b.Symbols().New("tint_workgroupUniformLoad");
         b.Func(name,
                utils::Vector{
-                   b.Param("p", b.ty.pointer(T(type), type::AddressSpace::kWorkgroup)),
+                   b.Param("p", b.ty.pointer(T(type), builtin::AddressSpace::kWorkgroup)),
                },
                T(type),
                utils::Vector{
@@ -1040,7 +1040,7 @@
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(sem::ParameterUsage::kTexture);
                             if (auto* stex = tex->Type()->As<type::StorageTexture>()) {
-                                if (stex->texel_format() == type::TexelFormat::kBgra8Unorm) {
+                                if (stex->texel_format() == builtin::TexelFormat::kBgra8Unorm) {
                                     size_t value_idx = static_cast<size_t>(
                                         sig.IndexOf(sem::ParameterUsage::kValue));
                                     ctx.Replace(expr, [&ctx, expr, value_idx] {
@@ -1140,10 +1140,11 @@
                 if (polyfill.bgra8unorm) {
                     if (auto* ty_expr = src->Sem().Get<sem::TypeExpression>(expr)) {
                         if (auto* tex = ty_expr->Type()->As<type::StorageTexture>()) {
-                            if (tex->texel_format() == type::TexelFormat::kBgra8Unorm) {
+                            if (tex->texel_format() == builtin::TexelFormat::kBgra8Unorm) {
                                 ctx.Replace(expr, [&ctx, tex] {
                                     return ctx.dst->Expr(ctx.dst->ty.storage_texture(
-                                        tex->dim(), type::TexelFormat::kRgba8Unorm, tex->access()));
+                                        tex->dim(), builtin::TexelFormat::kRgba8Unorm,
+                                        tex->access()));
                                 });
                                 made_changes = true;
                             }
diff --git a/src/tint/transform/builtin_polyfill_test.cc b/src/tint/transform/builtin_polyfill_test.cc
index 688d95e..09d17b8 100644
--- a/src/tint/transform/builtin_polyfill_test.cc
+++ b/src/tint/transform/builtin_polyfill_test.cc
@@ -52,7 +52,7 @@
     auto* src = R"(
 fn f() {
   let v = 1.0;
-  acosh(v);
+  _ = acosh(v);
 }
 )";
 
@@ -183,7 +183,7 @@
     auto* src = R"(
 fn f() {
   let v = 1.0;
-  asinh(v);
+  _ = asinh(v);
 }
 )";
 
@@ -264,7 +264,7 @@
     auto* src = R"(
 fn f() {
   let v = 1.0;
-  atanh(v);
+  _ = atanh(v);
 }
 )";
 
@@ -666,7 +666,7 @@
     auto* src = R"(
 fn f() {
   let v = 1i;
-  clamp(v, 2i, 3i);
+  _ = clamp(v, 2i, 3i);
 }
 )";
 
@@ -678,7 +678,7 @@
     auto* src = R"(
 fn f() {
   let v = 1u;
-  clamp(v, 2u, 3u);
+  _ = clamp(v, 2u, 3u);
 }
 )";
 
@@ -690,7 +690,7 @@
     auto* src = R"(
 fn f() {
   let v = 1f;
-  clamp(v, 2f, 3f);
+  _ = clamp(v, 2f, 3f);
 }
 )";
 
@@ -704,7 +704,7 @@
 
 fn f() {
   let v = 1h;
-  clamp(v, 2h, 3h);
+  _ = clamp(v, 2h, 3h);
 }
 )";
 
@@ -829,7 +829,7 @@
     auto* src = R"(
 fn f() {
   let v = 15;
-  countLeadingZeros(v);
+  _ = countLeadingZeros(v);
 }
 )";
 
@@ -1002,7 +1002,7 @@
     auto* src = R"(
 fn f() {
   let v = 15;
-  countTrailingZeros(v);
+  _ = countTrailingZeros(v);
 }
 )";
 
@@ -1175,7 +1175,7 @@
     auto* src = R"(
 fn f() {
   let v = 1234i;
-  extractBits(v, 5u, 6u);
+  _ = extractBits(v, 5u, 6u);
 }
 )";
 
@@ -1430,7 +1430,7 @@
     auto* src = R"(
 fn f() {
   let v = 15i;
-  firstLeadingBit(v);
+  _ = firstLeadingBit(v);
 }
 )";
 
@@ -1603,7 +1603,7 @@
     auto* src = R"(
 fn f() {
   let v = 15i;
-  firstTrailingBit(v);
+  _ = firstTrailingBit(v);
 }
 )";
 
@@ -1776,7 +1776,7 @@
     auto* src = R"(
 fn f() {
   let v = 1234i;
-  insertBits(v, 5678, 5u, 6u);
+  _ = insertBits(v, 5678, 5u, 6u);
 }
 )";
 
@@ -3059,7 +3059,7 @@
     auto* src = R"(
 fn f() {
   let v = 0.5f;
-  saturate(v);
+  _ = saturate(v);
 }
 )";
 
@@ -3196,7 +3196,7 @@
     auto* src = R"(
 fn f() {
   let v = 1i;
-  sign(v);
+  _ = sign(v);
 }
 )";
 
@@ -3208,7 +3208,7 @@
     auto* src = R"(
 fn f() {
   let v = 1f;
-  sign(v);
+  _ = sign(v);
 }
 )";
 
@@ -3291,7 +3291,7 @@
 @group(0) @binding(1) var s : sampler;
 
 fn f() {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(0.5));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(0.5));
 }
 )";
 
@@ -3305,7 +3305,7 @@
 @group(0) @binding(1) var s : sampler;
 
 fn f() {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(0.5));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(0.5));
 }
 )";
 
@@ -3361,7 +3361,7 @@
 var<workgroup> v : i32;
 
 fn f() {
-  workgroupUniformLoad(&v);
+  _ = workgroupUniformLoad(&v);
 }
 )";
 
@@ -3523,7 +3523,7 @@
     auto* src = R"(
 fn f() {
   let v = 0.5;
-  quantizeToF16(0.5);
+  _ = quantizeToF16(0.5);
 }
 )";
 
@@ -3535,7 +3535,7 @@
     auto* src = R"(
 fn f() {
   let v = 0.5;
-  quantizeToF16(vec2(v));
+  _ = quantizeToF16(vec2(v));
 }
 )";
 
@@ -3547,7 +3547,7 @@
     auto* src = R"(
 fn f() {
   let v = 0.5;
-  quantizeToF16(vec2(v));
+  _ = quantizeToF16(vec2(v));
 }
 )";
 
@@ -3558,7 +3558,7 @@
 
 fn f() {
   let v = 0.5;
-  tint_quantizeToF16(vec2(v));
+  _ = tint_quantizeToF16(vec2(v));
 }
 )";
 
@@ -3571,7 +3571,7 @@
     auto* src = R"(
 fn f() {
   let v = 0.5;
-  quantizeToF16(vec3(v));
+  _ = quantizeToF16(vec3(v));
 }
 )";
 
@@ -3582,7 +3582,7 @@
 
 fn f() {
   let v = 0.5;
-  tint_quantizeToF16(vec3(v));
+  _ = tint_quantizeToF16(vec3(v));
 }
 )";
 
@@ -3595,7 +3595,7 @@
     auto* src = R"(
 fn f() {
   let v = 0.5;
-  quantizeToF16(vec4(v));
+  _ = quantizeToF16(vec4(v));
 }
 )";
 
@@ -3606,7 +3606,7 @@
 
 fn f() {
   let v = 0.5;
-  tint_quantizeToF16(vec4(v));
+  _ = tint_quantizeToF16(vec4(v));
 }
 )";
 
diff --git a/src/tint/transform/calculate_array_length.cc b/src/tint/transform/calculate_array_length.cc
index 5ed6547..a25c89e 100644
--- a/src/tint/transform/calculate_array_length.cc
+++ b/src/tint/transform/calculate_array_length.cc
@@ -112,7 +112,7 @@
                     b.Param("buffer",
                             b.ty.pointer(type, buffer_type->AddressSpace(), buffer_type->Access()),
                             utils::Vector{disable_validation}),
-                    b.Param("result", b.ty.pointer(b.ty.u32(), type::AddressSpace::kFunction)),
+                    b.Param("result", b.ty.pointer(b.ty.u32(), builtin::AddressSpace::kFunction)),
                 },
                 b.ty.void_(), nullptr,
                 utils::Vector{
diff --git a/src/tint/transform/calculate_array_length_test.cc b/src/tint/transform/calculate_array_length_test.cc
index 826ffd6..98f2ed7 100644
--- a/src/tint/transform/calculate_array_length_test.cc
+++ b/src/tint/transform/calculate_array_length_test.cc
@@ -547,37 +547,5 @@
     EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CalculateArrayLengthTest, CallStatement) {
-    auto* src = R"(
-struct SB {
-  arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> a : SB;
-
-@compute @workgroup_size(1)
-fn main() {
-  arrayLength(&a.arr);
-}
-)";
-
-    auto* expect =
-        R"(
-struct SB {
-  arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> a : SB;
-
-@compute @workgroup_size(1)
-fn main() {
-}
-)";
-
-    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
 }  // namespace
 }  // namespace tint::transform
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/transform/canonicalize_entry_point_io.cc
index 049e9ca..3c9c6d0 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/transform/canonicalize_entry_point_io.cc
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "src/tint/ast/disable_validation_attribute.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/transform/unshadow.h"
@@ -81,46 +82,12 @@
     return 0;
 }
 
-/// Comparison function used to reorder struct members such that all members with
-/// location attributes appear first (ordered by location slot), followed by
-/// those with builtin attributes.
-/// @param a a struct member
-/// @param b another struct member
-/// @returns true if a comes before b
-bool StructMemberComparator(const MemberInfo& a, const MemberInfo& b) {
-    auto* a_loc = ast::GetAttribute<ast::LocationAttribute>(a.member->attributes);
-    auto* b_loc = ast::GetAttribute<ast::LocationAttribute>(b.member->attributes);
-    auto* a_blt = ast::GetAttribute<ast::BuiltinAttribute>(a.member->attributes);
-    auto* b_blt = ast::GetAttribute<ast::BuiltinAttribute>(b.member->attributes);
-    if (a_loc) {
-        if (!b_loc) {
-            // `a` has location attribute and `b` does not: `a` goes first.
-            return true;
-        }
-        // Both have location attributes: smallest goes first.
-        return a.location < b.location;
-    } else {
-        if (b_loc) {
-            // `b` has location attribute and `a` does not: `b` goes first.
-            return false;
-        }
-        // Both are builtins: order matters for FXC.
-        return BuiltinOrder(a_blt->builtin) < BuiltinOrder(b_blt->builtin);
-    }
-}
-
 // Returns true if `attr` is a shader IO attribute.
 bool IsShaderIOAttribute(const ast::Attribute* attr) {
     return attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute, ast::InvariantAttribute,
                          ast::LocationAttribute>();
 }
 
-// Returns true if `attrs` contains a `sample_mask` builtin.
-bool HasSampleMask(utils::VectorRef<const ast::Attribute*> attrs) {
-    auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attrs);
-    return builtin && builtin->builtin == builtin::BuiltinValue::kSampleMask;
-}
-
 }  // namespace
 
 /// PIMPL state for the transform
@@ -132,7 +99,7 @@
         /// The type of the output value.
         ast::Type type;
         /// The shader IO attributes.
-        utils::Vector<const ast::Attribute*, 2> attributes;
+        utils::Vector<const ast::Attribute*, 8> attributes;
         /// The value itself.
         const ast::Expression* value;
         /// The output location.
@@ -165,6 +132,8 @@
     utils::Vector<const ast::Statement*, 8> wrapper_body;
     /// Input names used by the entrypoint
     std::unordered_set<std::string> input_names;
+    /// A map of cloned attribute to builtin value
+    utils::Hashmap<const ast::BuiltinAttribute*, builtin::BuiltinValue, 16> builtin_attrs;
 
     /// Constructor
     /// @param context the clone context
@@ -175,20 +144,64 @@
           const ast::Function* function)
         : ctx(context), cfg(config), func_ast(function), func_sem(ctx.src->Sem().Get(function)) {}
 
-    /// Clones the shader IO attributes from `src`.
-    /// @param src the attributes to clone
+    /// Clones the attributes from @p in and adds it to @p out. If @p in is a builtin attribute,
+    /// then builtin_attrs is updated with the builtin information.
+    /// @param in the attribute to clone
+    /// @param out the output Attributes
+    template <size_t N>
+    void CloneAttribute(const ast::Attribute* in, utils::Vector<const ast::Attribute*, N>& out) {
+        auto* cloned = ctx.Clone(in);
+        out.Push(cloned);
+        if (auto* builtin = in->As<ast::BuiltinAttribute>()) {
+            builtin_attrs.Add(cloned->As<ast::BuiltinAttribute>(),
+                              ctx.src->Sem().Get(builtin)->Value());
+        }
+    }
+
+    /// Clones the shader IO attributes from @p in.
+    /// @param in the attributes to clone
     /// @param do_interpolate whether to clone InterpolateAttribute
     /// @return the cloned attributes
     template <size_t N>
-    auto CloneShaderIOAttributes(utils::Vector<const ast::Attribute*, N> src, bool do_interpolate) {
-        utils::Vector<const ast::Attribute*, N> new_attributes;
-        for (auto* attr : src) {
+    auto CloneShaderIOAttributes(const utils::Vector<const ast::Attribute*, N> in,
+                                 bool do_interpolate) {
+        utils::Vector<const ast::Attribute*, N> out;
+        for (auto* attr : in) {
             if (IsShaderIOAttribute(attr) &&
                 (do_interpolate || !attr->template Is<ast::InterpolateAttribute>())) {
-                new_attributes.Push(ctx.Clone(attr));
+                CloneAttribute(attr, out);
             }
         }
-        return new_attributes;
+        return out;
+    }
+
+    /// @param attr the input attribute
+    /// @returns the builtin value of the attribute
+    builtin::BuiltinValue BuiltinOf(const ast::BuiltinAttribute* attr) {
+        if (attr->program_id == ctx.dst->ID()) {
+            // attr belongs to the target program.
+            // Obtain the builtin value from #builtin_attrs.
+            if (auto b = builtin_attrs.Get(attr)) {
+                return *b;
+            }
+        } else {
+            // attr belongs to the source program.
+            // Obtain the builtin value from the semantic info.
+            return ctx.src->Sem().Get(attr)->Value();
+        }
+        TINT_ICE(Resolver, ctx.dst->Diagnostics())
+            << "could not obtain builtin value from attribute";
+        return builtin::BuiltinValue::kUndefined;
+    }
+
+    /// @param attrs the input attribute list
+    /// @returns the builtin value if any of the attributes in @p attrs is a builtin attribute,
+    /// otherwise builtin::BuiltinValue::kUndefined
+    builtin::BuiltinValue BuiltinOf(utils::VectorRef<const ast::Attribute*> attrs) {
+        if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attrs)) {
+            return BuiltinOf(builtin);
+        }
+        return builtin::BuiltinValue::kUndefined;
     }
 
     /// Create or return a symbol for the wrapper function's struct parameter.
@@ -204,13 +217,16 @@
     /// @param name the name of the shader input
     /// @param type the type of the shader input
     /// @param location the location if provided
-    /// @param attributes the attributes to apply to the shader input
+    /// @param attrs the attributes to apply to the shader input
     /// @returns an expression which evaluates to the value of the shader input
     const ast::Expression* AddInput(std::string name,
                                     const type::Type* type,
                                     std::optional<uint32_t> location,
-                                    utils::Vector<const ast::Attribute*, 8> attributes) {
+                                    utils::Vector<const ast::Attribute*, 8> attrs) {
         auto ast_type = CreateASTTypeFor(ctx, type);
+
+        auto builtin_attr = BuiltinOf(attrs);
+
         if (cfg.shader_style == ShaderStyle::kSpirv || cfg.shader_style == ShaderStyle::kGlsl) {
             // Vulkan requires that integer user-defined fragment inputs are always decorated with
             // `Flat`. See:
@@ -219,54 +235,54 @@
             // required for integers.
             if (func_ast->PipelineStage() == ast::PipelineStage::kFragment &&
                 type->is_integer_scalar_or_vector() &&
-                !ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
-                (ast::HasAttribute<ast::LocationAttribute>(attributes) ||
+                !ast::HasAttribute<ast::InterpolateAttribute>(attrs) &&
+                (ast::HasAttribute<ast::LocationAttribute>(attrs) ||
                  cfg.shader_style == ShaderStyle::kSpirv)) {
-                attributes.Push(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
-                                                     ast::InterpolationSampling::kUndefined));
+                attrs.Push(ctx.dst->Interpolate(builtin::InterpolationType::kFlat,
+                                                builtin::InterpolationSampling::kUndefined));
             }
 
             // Disable validation for use of the `input` address space.
-            attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace));
+            attrs.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace));
 
             // In GLSL, if it's a builtin, override the name with the
             // corresponding gl_ builtin name
-            auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attributes);
-            if (cfg.shader_style == ShaderStyle::kGlsl && builtin) {
-                name = GLSLBuiltinToString(builtin->builtin, func_ast->PipelineStage(),
-                                           type::AddressSpace::kIn);
+            if (cfg.shader_style == ShaderStyle::kGlsl &&
+                builtin_attr != builtin::BuiltinValue::kUndefined) {
+                name = GLSLBuiltinToString(builtin_attr, func_ast->PipelineStage(),
+                                           builtin::AddressSpace::kIn);
             }
             auto symbol = ctx.dst->Symbols().New(name);
 
             // Create the global variable and use its value for the shader input.
             const ast::Expression* value = ctx.dst->Expr(symbol);
 
-            if (builtin) {
+            if (builtin_attr != builtin::BuiltinValue::kUndefined) {
                 if (cfg.shader_style == ShaderStyle::kGlsl) {
-                    value = FromGLSLBuiltin(builtin->builtin, value, ast_type);
-                } else if (builtin->builtin == builtin::BuiltinValue::kSampleMask) {
+                    value = FromGLSLBuiltin(builtin_attr, value, ast_type);
+                } else if (builtin_attr == builtin::BuiltinValue::kSampleMask) {
                     // Vulkan requires the type of a SampleMask builtin to be an array.
                     // Declare it as array<u32, 1> and then load the first element.
                     ast_type = ctx.dst->ty.array(ast_type, 1_u);
                     value = ctx.dst->IndexAccessor(value, 0_i);
                 }
             }
-            ctx.dst->GlobalVar(symbol, ast_type, type::AddressSpace::kIn, std::move(attributes));
+            ctx.dst->GlobalVar(symbol, ast_type, builtin::AddressSpace::kIn, std::move(attrs));
             return value;
         } else if (cfg.shader_style == ShaderStyle::kMsl &&
-                   ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
+                   builtin_attr != builtin::BuiltinValue::kUndefined) {
             // If this input is a builtin and we are targeting MSL, then add it to the
             // parameter list and pass it directly to the inner function.
             Symbol symbol = input_names.emplace(name).second ? ctx.dst->Symbols().Register(name)
                                                              : ctx.dst->Symbols().New(name);
-            wrapper_ep_parameters.Push(ctx.dst->Param(symbol, ast_type, std::move(attributes)));
+            wrapper_ep_parameters.Push(ctx.dst->Param(symbol, ast_type, std::move(attrs)));
             return ctx.dst->Expr(symbol);
         } else {
             // Otherwise, move it to the new structure member list.
             Symbol symbol = input_names.emplace(name).second ? ctx.dst->Symbols().Register(name)
                                                              : ctx.dst->Symbols().New(name);
             wrapper_struct_param_members.Push(
-                {ctx.dst->Member(symbol, ast_type, std::move(attributes)), location});
+                {ctx.dst->Member(symbol, ast_type, std::move(attrs)), location});
             return ctx.dst->MemberAccessor(InputStructSymbol(), symbol);
         }
     }
@@ -275,13 +291,14 @@
     /// @param name the name of the shader output
     /// @param type the type of the shader output
     /// @param location the location if provided
-    /// @param attributes the attributes to apply to the shader output
+    /// @param attrs the attributes to apply to the shader output
     /// @param value the value of the shader output
     void AddOutput(std::string name,
                    const type::Type* type,
                    std::optional<uint32_t> location,
-                   utils::Vector<const ast::Attribute*, 8> attributes,
+                   utils::Vector<const ast::Attribute*, 8> attrs,
                    const ast::Expression* value) {
+        auto builtin_attr = BuiltinOf(attrs);
         // Vulkan requires that integer user-defined vertex outputs are always decorated with
         // `Flat`.
         // TODO(crbug.com/tint/1224): Remove this once a flat interpolation attribute is required
@@ -289,26 +306,26 @@
         if (cfg.shader_style == ShaderStyle::kSpirv &&
             func_ast->PipelineStage() == ast::PipelineStage::kVertex &&
             type->is_integer_scalar_or_vector() &&
-            ast::HasAttribute<ast::LocationAttribute>(attributes) &&
-            !ast::HasAttribute<ast::InterpolateAttribute>(attributes)) {
-            attributes.Push(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
-                                                 ast::InterpolationSampling::kUndefined));
+            ast::HasAttribute<ast::LocationAttribute>(attrs) &&
+            !ast::HasAttribute<ast::InterpolateAttribute>(attrs)) {
+            attrs.Push(ctx.dst->Interpolate(builtin::InterpolationType::kFlat,
+                                            builtin::InterpolationSampling::kUndefined));
         }
 
         // In GLSL, if it's a builtin, override the name with the
         // corresponding gl_ builtin name
         if (cfg.shader_style == ShaderStyle::kGlsl) {
-            if (auto* b = ast::GetAttribute<ast::BuiltinAttribute>(attributes)) {
-                name = GLSLBuiltinToString(b->builtin, func_ast->PipelineStage(),
-                                           type::AddressSpace::kOut);
-                value = ToGLSLBuiltin(b->builtin, value, type);
+            if (builtin_attr != builtin::BuiltinValue::kUndefined) {
+                name = GLSLBuiltinToString(builtin_attr, func_ast->PipelineStage(),
+                                           builtin::AddressSpace::kOut);
+                value = ToGLSLBuiltin(builtin_attr, value, type);
             }
         }
 
         OutputValue output;
         output.name = name;
         output.type = CreateASTTypeFor(ctx, type);
-        output.attributes = std::move(attributes);
+        output.attributes = std::move(attrs);
         output.value = value;
         output.location = location;
         wrapper_output_values.Push(output);
@@ -322,14 +339,14 @@
     void ProcessNonStructParameter(const sem::Parameter* param) {
         // Do not add interpolation attributes on vertex input
         bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kVertex;
-        // Remove the shader IO attributes from the inner function parameter, and
-        // attach them to the new object instead.
+        // Remove the shader IO attributes from the inner function parameter, and attach them to the
+        // new object instead.
         utils::Vector<const ast::Attribute*, 8> attributes;
         for (auto* attr : param->Declaration()->attributes) {
             if (IsShaderIOAttribute(attr)) {
                 ctx.Remove(param->Declaration()->attributes, attr);
                 if ((do_interpolate || !attr->Is<ast::InterpolateAttribute>())) {
-                    attributes.Push(ctx.Clone(attr));
+                    CloneAttribute(attr, attributes);
                 }
             }
         }
@@ -412,25 +429,28 @@
     void AddFixedSampleMask() {
         // Check the existing output values for a sample mask builtin.
         for (auto& outval : wrapper_output_values) {
-            if (HasSampleMask(outval.attributes)) {
+            if (BuiltinOf(outval.attributes) == builtin::BuiltinValue::kSampleMask) {
                 // Combine the authored sample mask with the fixed mask.
                 outval.value = ctx.dst->And(outval.value, u32(cfg.fixed_sample_mask));
                 return;
             }
         }
 
-        // No existing sample mask builtin was found, so create a new output value
-        // using the fixed sample mask.
-        AddOutput("fixed_sample_mask", ctx.dst->create<type::U32>(), std::nullopt,
-                  {ctx.dst->Builtin(builtin::BuiltinValue::kSampleMask)},
+        // No existing sample mask builtin was found, so create a new output value using the fixed
+        // sample mask.
+        auto* builtin = ctx.dst->Builtin(builtin::BuiltinValue::kSampleMask);
+        builtin_attrs.Add(builtin, builtin::BuiltinValue::kSampleMask);
+        AddOutput("fixed_sample_mask", ctx.dst->create<type::U32>(), std::nullopt, {builtin},
                   ctx.dst->Expr(u32(cfg.fixed_sample_mask)));
     }
 
     /// Add a point size builtin to the wrapper function output.
     void AddVertexPointSize() {
         // Create a new output value and assign it a literal 1.0 value.
-        AddOutput("vertex_point_size", ctx.dst->create<type::F32>(), std::nullopt,
-                  {ctx.dst->Builtin(builtin::BuiltinValue::kPointSize)}, ctx.dst->Expr(1_f));
+        auto* builtin = ctx.dst->Builtin(builtin::BuiltinValue::kPointSize);
+        builtin_attrs.Add(builtin, builtin::BuiltinValue::kPointSize);
+        AddOutput("vertex_point_size", ctx.dst->create<type::F32>(), std::nullopt, {builtin},
+                  ctx.dst->Expr(1_f));
     }
 
     /// Create an expression for gl_Position.[component]
@@ -442,11 +462,40 @@
         return ctx.dst->MemberAccessor(ctx.dst->Expr(pos), c);
     }
 
+    /// Comparison function used to reorder struct members such that all members with
+    /// location attributes appear first (ordered by location slot), followed by
+    /// those with builtin attributes.
+    /// @param a a struct member
+    /// @param b another struct member
+    /// @returns true if a comes before b
+    bool StructMemberComparator(const MemberInfo& a, const MemberInfo& b) {
+        auto* a_loc = ast::GetAttribute<ast::LocationAttribute>(a.member->attributes);
+        auto* b_loc = ast::GetAttribute<ast::LocationAttribute>(b.member->attributes);
+        auto* a_blt = ast::GetAttribute<ast::BuiltinAttribute>(a.member->attributes);
+        auto* b_blt = ast::GetAttribute<ast::BuiltinAttribute>(b.member->attributes);
+        if (a_loc) {
+            if (!b_loc) {
+                // `a` has location attribute and `b` does not: `a` goes first.
+                return true;
+            }
+            // Both have location attributes: smallest goes first.
+            return a.location < b.location;
+        } else {
+            if (b_loc) {
+                // `b` has location attribute and `a` does not: `b` goes first.
+                return false;
+            }
+            // Both are builtins: order matters for FXC.
+            auto builtin_a = BuiltinOf(a_blt);
+            auto builtin_b = BuiltinOf(b_blt);
+            return BuiltinOrder(builtin_a) < BuiltinOrder(builtin_b);
+        }
+    }
     /// Create the wrapper function's struct parameter and type objects.
     void CreateInputStruct() {
         // Sort the struct members to satisfy HLSL interfacing matching rules.
         std::sort(wrapper_struct_param_members.begin(), wrapper_struct_param_members.end(),
-                  StructMemberComparator);
+                  [&](auto& a, auto& b) { return StructMemberComparator(a, b); });
 
         utils::Vector<const ast::StructMember*, 8> members;
         for (auto& mem : wrapper_struct_param_members) {
@@ -483,16 +532,17 @@
             }
             member_names.insert(ctx.dst->Symbols().NameFor(name));
 
-            wrapper_struct_output_members.Push(
-                {ctx.dst->Member(name, outval.type, std::move(outval.attributes)),
-                 outval.location});
+            wrapper_struct_output_members.Push({
+                ctx.dst->Member(name, outval.type, std::move(outval.attributes)),
+                outval.location,
+            });
             assignments.Push(
                 ctx.dst->Assign(ctx.dst->MemberAccessor(wrapper_result, name), outval.value));
         }
 
         // Sort the struct members to satisfy HLSL interfacing matching rules.
         std::sort(wrapper_struct_output_members.begin(), wrapper_struct_output_members.end(),
-                  StructMemberComparator);
+                  [&](auto& a, auto& b) { return StructMemberComparator(a, b); });
 
         utils::Vector<const ast::StructMember*, 8> members;
         for (auto& mem : wrapper_struct_output_members) {
@@ -519,20 +569,20 @@
     void CreateGlobalOutputVariables() {
         for (auto& outval : wrapper_output_values) {
             // Disable validation for use of the `output` address space.
-            utils::Vector<const ast::Attribute*, 8> attributes = std::move(outval.attributes);
+            auto attributes = std::move(outval.attributes);
             attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace));
 
             // Create the global variable and assign it the output value.
             auto name = ctx.dst->Symbols().New(outval.name);
             ast::Type type = outval.type;
             const ast::Expression* lhs = ctx.dst->Expr(name);
-            if (HasSampleMask(attributes)) {
+            if (BuiltinOf(attributes) == builtin::BuiltinValue::kSampleMask) {
                 // Vulkan requires the type of a SampleMask builtin to be an array.
                 // Declare it as array<u32, 1> and then store to the first element.
                 type = ctx.dst->ty.array(type, 1_u);
                 lhs = ctx.dst->IndexAccessor(lhs, 0_i);
             }
-            ctx.dst->GlobalVar(name, type, type::AddressSpace::kOut, std::move(attributes));
+            ctx.dst->GlobalVar(name, type, builtin::AddressSpace::kOut, std::move(attributes));
             wrapper_body.Push(ctx.dst->Assign(lhs, outval.value));
         }
     }
@@ -677,7 +727,7 @@
     /// @returns the gl_ string corresponding to that builtin
     const char* GLSLBuiltinToString(builtin::BuiltinValue builtin,
                                     ast::PipelineStage stage,
-                                    type::AddressSpace address_space) {
+                                    builtin::AddressSpace address_space) {
         switch (builtin) {
             case builtin::BuiltinValue::kPosition:
                 switch (stage) {
@@ -709,7 +759,7 @@
             case builtin::BuiltinValue::kSampleIndex:
                 return "gl_SampleID";
             case builtin::BuiltinValue::kSampleMask:
-                if (address_space == type::AddressSpace::kIn) {
+                if (address_space == builtin::AddressSpace::kIn) {
                     return "gl_SampleMaskIn";
                 } else {
                     return "gl_SampleMask";
diff --git a/src/tint/transform/canonicalize_entry_point_io_test.cc b/src/tint/transform/canonicalize_entry_point_io_test.cc
index 5af8a14..08b8430 100644
--- a/src/tint/transform/canonicalize_entry_point_io_test.cc
+++ b/src/tint/transform/canonicalize_entry_point_io_test.cc
@@ -67,11 +67,11 @@
 )";
 
     auto* expect = R"(
-@location(1) @internal(disable_validation__ignore_address_space) var<in> loc1_1 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> loc1_1 : f32;
 
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> loc2_1 : vec4<u32>;
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> loc2_1 : vec4<u32>;
 
-@builtin(position) @internal(disable_validation__ignore_address_space) var<in> coord_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__in> coord_1 : vec4<f32>;
 
 fn frag_main_inner(loc1 : f32, loc2 : vec4<u32>, coord : vec4<f32>) {
   var col : f32 = (coord.x * loc1);
@@ -164,7 +164,7 @@
 
 TEST_F(CanonicalizeEntryPointIOTest, Parameter_TypeAlias) {
     auto* src = R"(
-type myf32 = f32;
+alias myf32 = f32;
 
 @fragment
 fn frag_main(@location(1) loc1 : myf32) {
@@ -204,7 +204,7 @@
   var x : myf32 = loc1;
 }
 
-type myf32 = f32;
+alias myf32 = f32;
 )";
 
     auto* expect = R"(
@@ -251,13 +251,13 @@
 )";
 
     auto* expect = R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<in> loc0_1 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> loc0_1 : f32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> loc1_1 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> loc1_1 : f32;
 
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> loc2_1 : vec4<u32>;
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> loc2_1 : vec4<u32>;
 
-@builtin(position) @internal(disable_validation__ignore_address_space) var<in> coord_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__in> coord_1 : vec4<f32>;
 
 struct FragBuiltins {
   coord : vec4<f32>,
@@ -304,13 +304,13 @@
 )";
 
     auto* expect = R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<in> loc0_1 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> loc0_1 : f32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> loc1_1 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> loc1_1 : f32;
 
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> loc2_1 : vec4<u32>;
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> loc2_1 : vec4<u32>;
 
-@builtin(position) @internal(disable_validation__ignore_address_space) var<in> coord_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__in> coord_1 : vec4<f32>;
 
 fn frag_main_inner(loc0 : f32, locations : FragLocations, builtins : FragBuiltins) {
   var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
@@ -567,7 +567,7 @@
 )";
 
     auto* expect = R"(
-@builtin(frag_depth) @internal(disable_validation__ignore_address_space) var<out> value : f32;
+@builtin(frag_depth) @internal(disable_validation__ignore_address_space) var<__out> value : f32;
 
 fn frag_main_inner() -> f32 {
   return 1.0;
@@ -674,11 +674,11 @@
 )";
 
     auto* expect = R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<out> color_1 : vec4<f32>;
+@location(0) @internal(disable_validation__ignore_address_space) var<__out> color_1 : vec4<f32>;
 
-@builtin(frag_depth) @internal(disable_validation__ignore_address_space) var<out> depth_1 : f32;
+@builtin(frag_depth) @internal(disable_validation__ignore_address_space) var<__out> depth_1 : f32;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<out> mask_1 : array<u32, 1u>;
+@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<__out> mask_1 : array<u32, 1u>;
 
 struct FragOutput {
   color : vec4<f32>,
@@ -729,11 +729,11 @@
 )";
 
     auto* expect = R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<out> color_1 : vec4<f32>;
+@location(0) @internal(disable_validation__ignore_address_space) var<__out> color_1 : vec4<f32>;
 
-@builtin(frag_depth) @internal(disable_validation__ignore_address_space) var<out> depth_1 : f32;
+@builtin(frag_depth) @internal(disable_validation__ignore_address_space) var<__out> depth_1 : f32;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<out> mask_1 : array<u32, 1u>;
+@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<__out> mask_1 : array<u32, 1u>;
 
 fn frag_main_inner() -> FragOutput {
   var output : FragOutput;
@@ -1028,13 +1028,13 @@
 )";
 
     auto* expect = R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<in> value_1 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> value_1 : f32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> mul_1 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> mul_1 : f32;
 
-@location(0) @internal(disable_validation__ignore_address_space) var<in> value_2 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> value_2 : f32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> mul_2 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> mul_2 : f32;
 
 struct FragmentInput {
   value : f32,
@@ -1094,13 +1094,13 @@
 )";
 
     auto* expect = R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<in> value_1 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> value_1 : f32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> mul_1 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> mul_1 : f32;
 
-@location(0) @internal(disable_validation__ignore_address_space) var<in> value_2 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> value_2 : f32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> mul_2 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> mul_2 : f32;
 
 fn frag_main1_inner(inputs : FragmentInput) {
   var x : f32 = foo(inputs);
@@ -1561,7 +1561,7 @@
 
 TEST_F(CanonicalizeEntryPointIOTest, Struct_TypeAliases) {
     auto* src = R"(
-type myf32 = f32;
+alias myf32 = f32;
 
 struct FragmentInput {
   @location(0) col1 : myf32,
@@ -1573,9 +1573,9 @@
   @location(1) col2 : myf32,
 };
 
-type MyFragmentInput = FragmentInput;
+alias MyFragmentInput = FragmentInput;
 
-type MyFragmentOutput = FragmentOutput;
+alias MyFragmentOutput = FragmentOutput;
 
 fn foo(x : MyFragmentInput) -> myf32 {
   return x.col1;
@@ -1653,9 +1653,9 @@
   return MyFragmentOutput(x, inputs.col2);
 }
 
-type MyFragmentInput = FragmentInput;
+alias MyFragmentInput = FragmentInput;
 
-type MyFragmentOutput = FragmentOutput;
+alias MyFragmentOutput = FragmentOutput;
 
 fn foo(x : MyFragmentInput) -> myf32 {
   return x.col1;
@@ -1671,7 +1671,7 @@
   @location(1) col2 : myf32,
 };
 
-type myf32 = f32;
+alias myf32 = f32;
 )";
 
     auto* expect = R"(
@@ -1952,39 +1952,39 @@
 
     auto* expect =
         R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<in> i_1 : i32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> i_1 : i32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> u_1 : u32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> u_1 : u32;
 
-@location(2) @internal(disable_validation__ignore_address_space) var<in> vi_1 : vec4<i32>;
+@location(2) @internal(disable_validation__ignore_address_space) var<__in> vi_1 : vec4<i32>;
 
-@location(3) @internal(disable_validation__ignore_address_space) var<in> vu_1 : vec4<u32>;
+@location(3) @internal(disable_validation__ignore_address_space) var<__in> vu_1 : vec4<u32>;
 
-@location(0) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<out> i_2 : i32;
+@location(0) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__out> i_2 : i32;
 
-@location(1) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<out> u_2 : u32;
+@location(1) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__out> u_2 : u32;
 
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<out> vi_2 : vec4<i32>;
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__out> vi_2 : vec4<i32>;
 
-@location(3) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<out> vu_2 : vec4<u32>;
+@location(3) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__out> vu_2 : vec4<u32>;
 
-@builtin(position) @internal(disable_validation__ignore_address_space) var<out> pos_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__out> pos_1 : vec4<f32>;
 
-@location(0) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> i_3 : i32;
+@location(0) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> i_3 : i32;
 
-@location(1) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> u_3 : u32;
+@location(1) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> u_3 : u32;
 
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> vi_3 : vec4<i32>;
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> vi_3 : vec4<i32>;
 
-@location(3) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> vu_3 : vec4<u32>;
+@location(3) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> vu_3 : vec4<u32>;
 
-@location(0) @internal(disable_validation__ignore_address_space) var<out> i_4 : i32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__out> i_4 : i32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<out> u_4 : u32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__out> u_4 : u32;
 
-@location(2) @internal(disable_validation__ignore_address_space) var<out> vi_4 : vec4<i32>;
+@location(2) @internal(disable_validation__ignore_address_space) var<__out> vi_4 : vec4<i32>;
 
-@location(3) @internal(disable_validation__ignore_address_space) var<out> vu_4 : vec4<u32>;
+@location(3) @internal(disable_validation__ignore_address_space) var<__out> vu_4 : vec4<u32>;
 
 struct VertexIn {
   i : i32,
@@ -2082,39 +2082,39 @@
 
     auto* expect =
         R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<in> i_1 : i32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> i_1 : i32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> u_1 : u32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> u_1 : u32;
 
-@location(2) @internal(disable_validation__ignore_address_space) var<in> vi_1 : vec4<i32>;
+@location(2) @internal(disable_validation__ignore_address_space) var<__in> vi_1 : vec4<i32>;
 
-@location(3) @internal(disable_validation__ignore_address_space) var<in> vu_1 : vec4<u32>;
+@location(3) @internal(disable_validation__ignore_address_space) var<__in> vu_1 : vec4<u32>;
 
-@location(0) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<out> i_2 : i32;
+@location(0) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__out> i_2 : i32;
 
-@location(1) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<out> u_2 : u32;
+@location(1) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__out> u_2 : u32;
 
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<out> vi_2 : vec4<i32>;
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__out> vi_2 : vec4<i32>;
 
-@location(3) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<out> vu_2 : vec4<u32>;
+@location(3) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__out> vu_2 : vec4<u32>;
 
-@builtin(position) @internal(disable_validation__ignore_address_space) var<out> pos_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__out> pos_1 : vec4<f32>;
 
-@location(0) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> i_3 : i32;
+@location(0) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> i_3 : i32;
 
-@location(1) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> u_3 : u32;
+@location(1) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> u_3 : u32;
 
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> vi_3 : vec4<i32>;
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> vi_3 : vec4<i32>;
 
-@location(3) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> vu_3 : vec4<u32>;
+@location(3) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> vu_3 : vec4<u32>;
 
-@location(0) @internal(disable_validation__ignore_address_space) var<out> i_4 : i32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__out> i_4 : i32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<out> u_4 : u32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__out> u_4 : u32;
 
-@location(2) @internal(disable_validation__ignore_address_space) var<out> vi_4 : vec4<i32>;
+@location(2) @internal(disable_validation__ignore_address_space) var<__out> vi_4 : vec4<i32>;
 
-@location(3) @internal(disable_validation__ignore_address_space) var<out> vu_4 : vec4<u32>;
+@location(3) @internal(disable_validation__ignore_address_space) var<__out> vu_4 : vec4<u32>;
 
 fn vert_main_inner(in : VertexIn) -> VertexOut {
   return VertexOut(in.i, in.u, in.vi, in.vu, vec4<f32>());
@@ -3161,9 +3161,9 @@
 )";
 
     auto* expect = R"(
-@builtin(position) @internal(disable_validation__ignore_address_space) var<out> value : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__out> value : vec4<f32>;
 
-@builtin(point_size) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size : f32;
+@builtin(__point_size) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size : f32;
 
 fn vert_main_inner() -> vec4<f32> {
   return vec4<f32>();
@@ -3197,7 +3197,7 @@
 struct tint_symbol {
   @builtin(position)
   value : vec4<f32>,
-  @builtin(point_size)
+  @builtin(__point_size)
   vertex_point_size : f32,
 }
 
@@ -3236,9 +3236,9 @@
 )";
 
     auto* expect = R"(
-@builtin(position) @internal(disable_validation__ignore_address_space) var<out> pos_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__out> pos_1 : vec4<f32>;
 
-@builtin(point_size) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size : f32;
+@builtin(__point_size) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size : f32;
 
 struct VertOut {
   pos : vec4<f32>,
@@ -3277,9 +3277,9 @@
 )";
 
     auto* expect = R"(
-@builtin(position) @internal(disable_validation__ignore_address_space) var<out> pos_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__out> pos_1 : vec4<f32>;
 
-@builtin(point_size) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size : f32;
+@builtin(__point_size) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size : f32;
 
 fn vert_main_inner() -> VertOut {
   return VertOut();
@@ -3325,7 +3325,7 @@
 struct tint_symbol {
   @builtin(position)
   pos : vec4<f32>,
-  @builtin(point_size)
+  @builtin(__point_size)
   vertex_point_size : f32,
 }
 
@@ -3367,7 +3367,7 @@
 struct tint_symbol {
   @builtin(position)
   pos : vec4<f32>,
-  @builtin(point_size)
+  @builtin(__point_size)
   vertex_point_size : f32,
 }
 
@@ -3424,15 +3424,15 @@
 )";
 
     auto* expect = R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<in> collide_2 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> collide_2 : f32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> collide_3 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> collide_3 : f32;
 
-@location(0) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size_3 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size_3 : f32;
 
-@builtin(position) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size_1_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size_1_1 : vec4<f32>;
 
-@builtin(point_size) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size_4 : f32;
+@builtin(__point_size) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size_4 : f32;
 
 var<private> vertex_point_size : f32;
 
@@ -3502,15 +3502,15 @@
 )";
 
     auto* expect = R"(
-@location(0) @internal(disable_validation__ignore_address_space) var<in> collide_2 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__in> collide_2 : f32;
 
-@location(1) @internal(disable_validation__ignore_address_space) var<in> collide_3 : f32;
+@location(1) @internal(disable_validation__ignore_address_space) var<__in> collide_3 : f32;
 
-@location(0) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size_3 : f32;
+@location(0) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size_3 : f32;
 
-@builtin(position) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size_1_1 : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size_1_1 : vec4<f32>;
 
-@builtin(point_size) @internal(disable_validation__ignore_address_space) var<out> vertex_point_size_4 : f32;
+@builtin(__point_size) @internal(disable_validation__ignore_address_space) var<__out> vertex_point_size_4 : f32;
 
 fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
   let x = (collide.collide + collide_1.collide);
@@ -3601,7 +3601,7 @@
   vertex_point_size : vec4<f32>,
   @builtin(position)
   vertex_point_size_1 : vec4<f32>,
-  @builtin(point_size)
+  @builtin(__point_size)
   vertex_point_size_2 : f32,
 }
 
@@ -3664,7 +3664,7 @@
   vertex_point_size : vec4<f32>,
   @builtin(position)
   vertex_point_size_1 : vec4<f32>,
-  @builtin(point_size)
+  @builtin(__point_size)
   vertex_point_size_2 : f32,
 }
 
@@ -3753,7 +3753,7 @@
   vertex_point_size : vec4<f32>,
   @builtin(position)
   vertex_point_size_1 : vec4<f32>,
-  @builtin(point_size)
+  @builtin(__point_size)
   vertex_point_size_2 : f32,
 }
 
@@ -3816,7 +3816,7 @@
   vertex_point_size : vec4<f32>,
   @builtin(position)
   vertex_point_size_1 : vec4<f32>,
-  @builtin(point_size)
+  @builtin(__point_size)
   vertex_point_size_2 : f32,
 }
 
@@ -3868,11 +3868,11 @@
 )";
 
     auto* expect = R"(
-@builtin(sample_index) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> sample_index_1 : u32;
+@builtin(sample_index) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> sample_index_1 : u32;
 
-@builtin(sample_mask) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<in> mask_in_1 : array<u32, 1u>;
+@builtin(sample_mask) @interpolate(flat) @internal(disable_validation__ignore_address_space) var<__in> mask_in_1 : array<u32, 1u>;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<out> value : array<u32, 1u>;
+@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<__out> value : array<u32, 1u>;
 
 fn main_inner(sample_index : u32, mask_in : u32) -> u32 {
   return mask_in;
@@ -3903,11 +3903,11 @@
 )";
 
     auto* expect = R"(
-@builtin(sample_index) @internal(disable_validation__ignore_address_space) var<in> gl_SampleID : i32;
+@builtin(sample_index) @internal(disable_validation__ignore_address_space) var<__in> gl_SampleID : i32;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<in> gl_SampleMaskIn : array<i32, 1u>;
+@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<__in> gl_SampleMaskIn : array<i32, 1u>;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<out> gl_SampleMask : array<i32, 1u>;
+@builtin(sample_mask) @internal(disable_validation__ignore_address_space) var<__out> gl_SampleMask : array<i32, 1u>;
 
 fn fragment_main(sample_index : u32, mask_in : u32) -> u32 {
   return mask_in;
@@ -3938,11 +3938,11 @@
 )";
 
     auto* expect = R"(
-@builtin(vertex_index) @internal(disable_validation__ignore_address_space) var<in> gl_VertexID : i32;
+@builtin(vertex_index) @internal(disable_validation__ignore_address_space) var<__in> gl_VertexID : i32;
 
-@builtin(instance_index) @internal(disable_validation__ignore_address_space) var<in> gl_InstanceID : i32;
+@builtin(instance_index) @internal(disable_validation__ignore_address_space) var<__in> gl_InstanceID : i32;
 
-@builtin(position) @internal(disable_validation__ignore_address_space) var<out> gl_Position : vec4<f32>;
+@builtin(position) @internal(disable_validation__ignore_address_space) var<__out> gl_Position : vec4<f32>;
 
 fn vertex_main(vertexID : u32, instanceID : u32) -> vec4<f32> {
   return vec4<f32>((f32(vertexID) + f32(instanceID)));
diff --git a/src/tint/transform/clamp_frag_depth.cc b/src/tint/transform/clamp_frag_depth.cc
index 57d9a40..77d897d 100644
--- a/src/tint/transform/clamp_frag_depth.cc
+++ b/src/tint/transform/clamp_frag_depth.cc
@@ -33,177 +33,196 @@
 
 namespace tint::transform {
 
-namespace {
+/// PIMPL state for the transform
+struct ClampFragDepth::State {
+    /// The source program
+    const Program* const src;
+    /// The target program builder
+    ProgramBuilder b{};
+    /// The clone context
+    CloneContext ctx = {&b, src, /* auto_clone_symbols */ true};
+    /// The sem::Info of the program
+    const sem::Info& sem = src->Sem();
+    /// The symbols of the program
+    const SymbolTable& sym = src->Symbols();
 
-bool ContainsFragDepth(utils::VectorRef<const ast::Attribute*> attributes) {
-    for (auto* attribute : attributes) {
-        if (auto* builtin_attribute = attribute->As<ast::BuiltinAttribute>()) {
-            if (builtin_attribute->builtin == builtin::BuiltinValue::kFragDepth) {
+    /// Runs the transform
+    /// @returns the new program or SkipTransform if the transform is not required
+    Transform::ApplyResult Run() {
+        // Abort on any use of push constants in the module.
+        for (auto* global : src->AST().GlobalVariables()) {
+            if (auto* var = global->As<ast::Var>()) {
+                auto* v = src->Sem().Get(var);
+                if (TINT_UNLIKELY(v->AddressSpace() == builtin::AddressSpace::kPushConstant)) {
+                    TINT_ICE(Transform, b.Diagnostics())
+                        << "ClampFragDepth doesn't know how to handle module that already use push "
+                           "constants";
+                    return Program(std::move(b));
+                }
+            }
+        }
+
+        if (!ShouldRun()) {
+            return SkipTransform;
+        }
+
+        // At least one entry-point needs clamping. Add the following to the module:
+        //
+        //   enable chromium_experimental_push_constant;
+        //
+        //   struct FragDepthClampArgs {
+        //       min : f32,
+        //       max : f32,
+        //   }
+        //   var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
+        //
+        //   fn clamp_frag_depth(v : f32) -> f32 {
+        //       return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
+        //   }
+        b.Enable(builtin::Extension::kChromiumExperimentalPushConstant);
+
+        b.Structure(b.Symbols().New("FragDepthClampArgs"),
+                    utils::Vector{b.Member("min", b.ty.f32()), b.Member("max", b.ty.f32())});
+
+        auto args_sym = b.Symbols().New("frag_depth_clamp_args");
+        b.GlobalVar(args_sym, b.ty("FragDepthClampArgs"), builtin::AddressSpace::kPushConstant);
+
+        auto base_fn_sym = b.Symbols().New("clamp_frag_depth");
+        b.Func(base_fn_sym, utils::Vector{b.Param("v", b.ty.f32())}, b.ty.f32(),
+               utils::Vector{b.Return(b.Call("clamp", "v", b.MemberAccessor(args_sym, "min"),
+                                             b.MemberAccessor(args_sym, "max")))});
+
+        // If true, the currently cloned function returns frag depth directly as a scalar
+        bool returns_frag_depth_as_value = false;
+
+        // If valid, the currently cloned function returns frag depth in a struct
+        // The symbol is the name of the helper function to apply the depth clamping.
+        Symbol returns_frag_depth_as_struct_helper;
+
+        // Map of io struct to helper function to return the structure with the depth clamping
+        // applied.
+        utils::Hashmap<const ast::Struct*, Symbol, 4u> io_structs_clamp_helpers;
+
+        // Register a callback that will be called for each visted AST function.
+        // This call wraps the cloning of the function's statements, and will assign to
+        // `returns_frag_depth_as_value` or `returns_frag_depth_as_struct_helper` if the function's
+        // return value requires depth clamping.
+        ctx.ReplaceAll([&](const ast::Function* fn) {
+            if (fn->PipelineStage() != ast::PipelineStage::kFragment) {
+                return ctx.CloneWithoutTransform(fn);
+            }
+
+            if (ReturnsFragDepthAsValue(fn)) {
+                TINT_SCOPED_ASSIGNMENT(returns_frag_depth_as_value, true);
+                return ctx.CloneWithoutTransform(fn);
+            }
+
+            if (ReturnsFragDepthInStruct(fn)) {
+                // At most once per I/O struct, add the conversion function:
+                //
+                //   fn clamp_frag_depth_S(s : S) -> S {
+                //       return S(s.first, s.second, clamp_frag_depth(s.frag_depth), s.last);
+                //   }
+                auto* struct_ty = sem.Get(fn)->ReturnType()->As<sem::Struct>()->Declaration();
+                auto helper = io_structs_clamp_helpers.GetOrCreate(struct_ty, [&] {
+                    auto return_ty = fn->return_type;
+                    auto fn_sym =
+                        b.Symbols().New("clamp_frag_depth_" + sym.NameFor(struct_ty->name->symbol));
+
+                    utils::Vector<const ast::Expression*, 8u> initializer_args;
+                    for (auto* member : struct_ty->members) {
+                        const ast::Expression* arg =
+                            b.MemberAccessor("s", ctx.Clone(member->name->symbol));
+                        if (ContainsFragDepth(member->attributes)) {
+                            arg = b.Call(base_fn_sym, arg);
+                        }
+                        initializer_args.Push(arg);
+                    }
+                    utils::Vector params{b.Param("s", ctx.Clone(return_ty))};
+                    utils::Vector body{
+                        b.Return(b.Call(ctx.Clone(return_ty), std::move(initializer_args))),
+                    };
+                    b.Func(fn_sym, params, ctx.Clone(return_ty), body);
+                    return fn_sym;
+                });
+
+                TINT_SCOPED_ASSIGNMENT(returns_frag_depth_as_struct_helper, helper);
+                return ctx.CloneWithoutTransform(fn);
+            }
+
+            return ctx.CloneWithoutTransform(fn);
+        });
+
+        // Replace the return statements `return expr` with `return clamp_frag_depth(expr)`.
+        ctx.ReplaceAll([&](const ast::ReturnStatement* stmt) -> const ast::ReturnStatement* {
+            if (returns_frag_depth_as_value) {
+                return b.Return(stmt->source, b.Call(base_fn_sym, ctx.Clone(stmt->value)));
+            }
+            if (returns_frag_depth_as_struct_helper.IsValid()) {
+                return b.Return(stmt->source, b.Call(returns_frag_depth_as_struct_helper,
+                                                     ctx.Clone(stmt->value)));
+            }
+            return nullptr;
+        });
+
+        ctx.Clone();
+        return Program(std::move(b));
+    }
+
+  private:
+    /// @returns true if the transform should run
+    bool ShouldRun() {
+        for (auto* fn : src->AST().Functions()) {
+            if (fn->PipelineStage() == ast::PipelineStage::kFragment &&
+                (ReturnsFragDepthAsValue(fn) || ReturnsFragDepthInStruct(fn))) {
                 return true;
             }
         }
+
+        return false;
     }
-
-    return false;
-}
-
-bool ReturnsFragDepthAsValue(const ast::Function* fn) {
-    return ContainsFragDepth(fn->return_type_attributes);
-}
-
-bool ReturnsFragDepthInStruct(const sem::Info& sem, const ast::Function* fn) {
-    if (auto* struct_ty = sem.Get(fn)->ReturnType()->As<sem::Struct>()) {
-        for (auto* member : struct_ty->Members()) {
-            if (ContainsFragDepth(member->Declaration()->attributes)) {
-                return true;
+    /// @param attrs the attributes to examine
+    /// @returns true if @p attrs contains a `@builtin(frag_depth)` attribute
+    bool ContainsFragDepth(utils::VectorRef<const ast::Attribute*> attrs) {
+        for (auto* attribute : attrs) {
+            if (auto* builtin_attr = attribute->As<ast::BuiltinAttribute>()) {
+                auto builtin = sem.Get(builtin_attr)->Value();
+                if (builtin == builtin::BuiltinValue::kFragDepth) {
+                    return true;
+                }
             }
         }
+
+        return false;
     }
 
-    return false;
-}
+    /// @param fn the function to examine
+    /// @returns true if @p fn has a return type with a `@builtin(frag_depth)` attribute
+    bool ReturnsFragDepthAsValue(const ast::Function* fn) {
+        return ContainsFragDepth(fn->return_type_attributes);
+    }
 
-bool ShouldRun(const Program* program) {
-    auto& sem = program->Sem();
-
-    for (auto* fn : program->AST().Functions()) {
-        if (fn->PipelineStage() == ast::PipelineStage::kFragment &&
-            (ReturnsFragDepthAsValue(fn) || ReturnsFragDepthInStruct(sem, fn))) {
-            return true;
+    /// @param fn the function to examine
+    /// @returns true if @p fn has a return structure with a `@builtin(frag_depth)` attribute on one
+    /// of the members
+    bool ReturnsFragDepthInStruct(const ast::Function* fn) {
+        if (auto* struct_ty = sem.Get(fn)->ReturnType()->As<sem::Struct>()) {
+            for (auto* member : struct_ty->Members()) {
+                if (ContainsFragDepth(member->Declaration()->attributes)) {
+                    return true;
+                }
+            }
         }
+
+        return false;
     }
-
-    return false;
-}
-
-}  // anonymous namespace
+};
 
 ClampFragDepth::ClampFragDepth() = default;
 ClampFragDepth::~ClampFragDepth() = default;
 
 Transform::ApplyResult ClampFragDepth::Apply(const Program* src, const DataMap&, DataMap&) const {
-    ProgramBuilder b;
-    CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
-
-    // Abort on any use of push constants in the module.
-    for (auto* global : src->AST().GlobalVariables()) {
-        if (auto* var = global->As<ast::Var>()) {
-            if (TINT_UNLIKELY(var->declared_address_space == type::AddressSpace::kPushConstant)) {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "ClampFragDepth doesn't know how to handle module that already use push "
-                       "constants.";
-                return Program(std::move(b));
-            }
-        }
-    }
-
-    if (!ShouldRun(src)) {
-        return SkipTransform;
-    }
-
-    auto& sem = src->Sem();
-    auto& sym = src->Symbols();
-
-    // At least one entry-point needs clamping. Add the following to the module:
-    //
-    //   enable chromium_experimental_push_constant;
-    //
-    //   struct FragDepthClampArgs {
-    //       min : f32,
-    //       max : f32,
-    //   }
-    //   var<push_constant> frag_depth_clamp_args : FragDepthClampArgs;
-    //
-    //   fn clamp_frag_depth(v : f32) -> f32 {
-    //       return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
-    //   }
-    b.Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-
-    b.Structure(b.Symbols().New("FragDepthClampArgs"),
-                utils::Vector{b.Member("min", b.ty.f32()), b.Member("max", b.ty.f32())});
-
-    auto args_sym = b.Symbols().New("frag_depth_clamp_args");
-    b.GlobalVar(args_sym, b.ty("FragDepthClampArgs"), type::AddressSpace::kPushConstant);
-
-    auto base_fn_sym = b.Symbols().New("clamp_frag_depth");
-    b.Func(base_fn_sym, utils::Vector{b.Param("v", b.ty.f32())}, b.ty.f32(),
-           utils::Vector{b.Return(b.Call("clamp", "v", b.MemberAccessor(args_sym, "min"),
-                                         b.MemberAccessor(args_sym, "max")))});
-
-    // If true, the currently cloned function returns frag depth directly as a scalar
-    bool returns_frag_depth_as_value = false;
-
-    // If valid, the currently cloned function returns frag depth in a struct
-    // The symbol is the name of the helper function to apply the depth clamping.
-    Symbol returns_frag_depth_as_struct_helper;
-
-    // Map of io struct to helper function to return the structure with the depth clamping applied.
-    utils::Hashmap<const ast::Struct*, Symbol, 4u> io_structs_clamp_helpers;
-
-    // Register a callback that will be called for each visted AST function.
-    // This call wraps the cloning of the function's statements, and will assign to
-    // `returns_frag_depth_as_value` or `returns_frag_depth_as_struct_helper` if the function's
-    // return value requires depth clamping.
-    ctx.ReplaceAll([&](const ast::Function* fn) {
-        if (fn->PipelineStage() != ast::PipelineStage::kFragment) {
-            return ctx.CloneWithoutTransform(fn);
-        }
-
-        if (ReturnsFragDepthAsValue(fn)) {
-            TINT_SCOPED_ASSIGNMENT(returns_frag_depth_as_value, true);
-            return ctx.CloneWithoutTransform(fn);
-        }
-
-        if (ReturnsFragDepthInStruct(sem, fn)) {
-            // At most once per I/O struct, add the conversion function:
-            //
-            //   fn clamp_frag_depth_S(s : S) -> S {
-            //       return S(s.first, s.second, clamp_frag_depth(s.frag_depth), s.last);
-            //   }
-            auto* struct_ty = sem.Get(fn)->ReturnType()->As<sem::Struct>()->Declaration();
-            auto helper = io_structs_clamp_helpers.GetOrCreate(struct_ty, [&] {
-                auto return_ty = fn->return_type;
-                auto fn_sym =
-                    b.Symbols().New("clamp_frag_depth_" + sym.NameFor(struct_ty->name->symbol));
-
-                utils::Vector<const ast::Expression*, 8u> initializer_args;
-                for (auto* member : struct_ty->members) {
-                    const ast::Expression* arg =
-                        b.MemberAccessor("s", ctx.Clone(member->name->symbol));
-                    if (ContainsFragDepth(member->attributes)) {
-                        arg = b.Call(base_fn_sym, arg);
-                    }
-                    initializer_args.Push(arg);
-                }
-                utils::Vector params{b.Param("s", ctx.Clone(return_ty))};
-                utils::Vector body{
-                    b.Return(b.Call(ctx.Clone(return_ty), std::move(initializer_args))),
-                };
-                b.Func(fn_sym, params, ctx.Clone(return_ty), body);
-                return fn_sym;
-            });
-
-            TINT_SCOPED_ASSIGNMENT(returns_frag_depth_as_struct_helper, helper);
-            return ctx.CloneWithoutTransform(fn);
-        }
-
-        return ctx.CloneWithoutTransform(fn);
-    });
-
-    // Replace the return statements `return expr` with `return clamp_frag_depth(expr)`.
-    ctx.ReplaceAll([&](const ast::ReturnStatement* stmt) -> const ast::ReturnStatement* {
-        if (returns_frag_depth_as_value) {
-            return b.Return(stmt->source, b.Call(base_fn_sym, ctx.Clone(stmt->value)));
-        }
-        if (returns_frag_depth_as_struct_helper.IsValid()) {
-            return b.Return(stmt->source,
-                            b.Call(returns_frag_depth_as_struct_helper, ctx.Clone(stmt->value)));
-        }
-        return nullptr;
-    });
-
-    ctx.Clone();
-    return Program(std::move(b));
+    return State{src}.Run();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/clamp_frag_depth.h b/src/tint/transform/clamp_frag_depth.h
index 1e9d0d6..3e3f168 100644
--- a/src/tint/transform/clamp_frag_depth.h
+++ b/src/tint/transform/clamp_frag_depth.h
@@ -65,6 +65,9 @@
     ApplyResult Apply(const Program* program,
                       const DataMap& inputs,
                       DataMap& outputs) const override;
+
+  private:
+    struct State;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/combine_samplers_test.cc b/src/tint/transform/combine_samplers_test.cc
index e400ed5..cfabded 100644
--- a/src/tint/transform/combine_samplers_test.cc
+++ b/src/tint/transform/combine_samplers_test.cc
@@ -232,7 +232,7 @@
 TEST_F(CombineSamplersTest, AliasedTypes) {
     auto* src = R"(
 
-type Tex2d = texture_2d<f32>;
+alias Tex2d = texture_2d<f32>;
 
 @group(0) @binding(0) var t : Tex2d;
 
@@ -282,7 +282,7 @@
 @group(0) @binding(0) var t : Tex2d;
 @group(0) @binding(1) var s : sampler;
 
-type Tex2d = texture_2d<f32>;
+alias Tex2d = texture_2d<f32>;
 )";
     auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
diff --git a/src/tint/transform/decompose_memory_access.cc b/src/tint/transform/decompose_memory_access.cc
index 072c9c6..28ecebd 100644
--- a/src/tint/transform/decompose_memory_access.cc
+++ b/src/tint/transform/decompose_memory_access.cc
@@ -49,8 +49,8 @@
 bool ShouldRun(const Program* program) {
     for (auto* decl : program->AST().GlobalDeclarations()) {
         if (auto* var = program->Sem().Get<sem::Variable>(decl)) {
-            if (var->AddressSpace() == type::AddressSpace::kStorage ||
-                var->AddressSpace() == type::AddressSpace::kUniform) {
+            if (var->AddressSpace() == builtin::AddressSpace::kStorage ||
+                var->AddressSpace() == builtin::AddressSpace::kUniform) {
                 return true;
             }
         }
@@ -108,33 +108,29 @@
 
 /// LoadStoreKey is the unordered map key to a load or store intrinsic.
 struct LoadStoreKey {
-    type::AddressSpace const address_space;  // buffer address space
-    type::Access const access;               // buffer access
-    type::Type const* buf_ty = nullptr;      // buffer type
-    type::Type const* el_ty = nullptr;       // element type
+    type::Type const* el_ty = nullptr;  // element type
+    Symbol const buffer;                // buffer name
     bool operator==(const LoadStoreKey& rhs) const {
-        return address_space == rhs.address_space && access == rhs.access && buf_ty == rhs.buf_ty &&
-               el_ty == rhs.el_ty;
+        return el_ty == rhs.el_ty && buffer == rhs.buffer;
     }
     struct Hasher {
         inline std::size_t operator()(const LoadStoreKey& u) const {
-            return utils::Hash(u.address_space, u.access, u.buf_ty, u.el_ty);
+            return utils::Hash(u.el_ty, u.buffer);
         }
     };
 };
 
 /// AtomicKey is the unordered map key to an atomic intrinsic.
 struct AtomicKey {
-    type::Access const access;           // buffer access
-    type::Type const* buf_ty = nullptr;  // buffer type
-    type::Type const* el_ty = nullptr;   // element type
-    sem::BuiltinType const op;           // atomic op
+    type::Type const* el_ty = nullptr;  // element type
+    sem::BuiltinType const op;          // atomic op
+    Symbol const buffer;                // buffer name
     bool operator==(const AtomicKey& rhs) const {
-        return access == rhs.access && buf_ty == rhs.buf_ty && el_ty == rhs.el_ty && op == rhs.op;
+        return el_ty == rhs.el_ty && op == rhs.op && buffer == rhs.buffer;
     }
     struct Hasher {
         inline std::size_t operator()(const AtomicKey& u) const {
-            return utils::Hash(u.access, u.buf_ty, u.el_ty, u.op);
+            return utils::Hash(u.el_ty, u.op, u.buffer);
         }
     };
 };
@@ -219,39 +215,41 @@
     return false;
 }
 
-/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
-/// to a stub function to load the type `ty`.
+/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function to
+/// load the type @p ty from the uniform or storage buffer with name @p buffer.
 DecomposeMemoryAccess::Intrinsic* IntrinsicLoadFor(ProgramBuilder* builder,
-                                                   type::AddressSpace address_space,
-                                                   const type::Type* ty) {
+                                                   const type::Type* ty,
+                                                   builtin::AddressSpace address_space,
+                                                   const Symbol& buffer) {
     DecomposeMemoryAccess::Intrinsic::DataType type;
     if (!IntrinsicDataTypeFor(ty, type)) {
         return nullptr;
     }
     return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
-        builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad,
-        address_space, type);
+        builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad, type,
+        address_space, buffer);
 }
 
-/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
-/// to a stub function to store the type `ty`.
+/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function to
+/// store the type @p ty to the storage buffer with name @p buffer.
 DecomposeMemoryAccess::Intrinsic* IntrinsicStoreFor(ProgramBuilder* builder,
-                                                    type::AddressSpace address_space,
-                                                    const type::Type* ty) {
+                                                    const type::Type* ty,
+                                                    const Symbol& buffer) {
     DecomposeMemoryAccess::Intrinsic::DataType type;
     if (!IntrinsicDataTypeFor(ty, type)) {
         return nullptr;
     }
     return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
         builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kStore,
-        address_space, type);
+        type, builtin::AddressSpace::kStorage, buffer);
 }
 
-/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
-/// to a stub function for the atomic op and the type `ty`.
+/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function for
+/// the atomic op and the type @p ty.
 DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ProgramBuilder* builder,
                                                      sem::BuiltinType ity,
-                                                     const type::Type* ty) {
+                                                     const type::Type* ty,
+                                                     const Symbol& buffer) {
     auto op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
     switch (ity) {
         case sem::BuiltinType::kAtomicLoad:
@@ -299,15 +297,16 @@
         return nullptr;
     }
     return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
-        builder->ID(), builder->AllocateNodeID(), op, type::AddressSpace::kStorage, type);
+        builder->ID(), builder->AllocateNodeID(), op, type, builtin::AddressSpace::kStorage,
+        buffer);
 }
 
 /// BufferAccess describes a single storage or uniform buffer access
 struct BufferAccess {
-    sem::ValueExpression const* var = nullptr;  // Storage buffer variable
-    Offset const* offset = nullptr;             // The byte offset on var
-    type::Type const* type = nullptr;           // The type of the access
-    operator bool() const { return var; }       // Returns true if valid
+    sem::GlobalVariable const* var = nullptr;  // Storage or uniform buffer variable
+    Offset const* offset = nullptr;            // The byte offset on var
+    type::Type const* type = nullptr;          // The type of the access
+    operator bool() const { return var; }      // Returns true if valid
 };
 
 /// Store describes a single storage or uniform buffer write
@@ -452,238 +451,194 @@
         return access;
     }
 
-    /// LoadFunc() returns a symbol to an intrinsic function that loads an element of type `el_ty`
-    /// from a storage or uniform buffer of type `buf_ty`.
+    /// LoadFunc() returns a symbol to an intrinsic function that loads an element of type @p el_ty
+    /// from a storage or uniform buffer with name @p buffer.
     /// The emitted function has the signature:
-    ///   `fn load(buf : ptr<SC, buf_ty, A>, offset : u32) -> el_ty`
-    /// @param buf_ty the storage or uniform buffer type
+    ///   `fn load(offset : u32) -> el_ty`
     /// @param el_ty the storage or uniform buffer element type
-    /// @param var_user the variable user
+    /// @param address_space either kUniform or kStorage
+    /// @param buffer the symbol of the storage or uniform buffer variable, owned by the target
+    /// ProgramBuilder.
     /// @return the name of the function that performs the load
-    Symbol LoadFunc(const type::Type* buf_ty,
-                    const type::Type* el_ty,
-                    const sem::VariableUser* var_user) {
-        auto address_space = var_user->Variable()->AddressSpace();
-        auto access = var_user->Variable()->Access();
-        if (address_space != type::AddressSpace::kStorage) {
-            access = type::Access::kUndefined;
-        }
-        return utils::GetOrCreate(
-            load_funcs, LoadStoreKey{address_space, access, buf_ty, el_ty}, [&] {
-                utils::Vector params{
-                    b.Param("buffer",
-                            b.ty.pointer(CreateASTTypeFor(ctx, buf_ty), address_space, access),
-                            utils::Vector{b.Disable(ast::DisabledValidation::kFunctionParameter)}),
-                    b.Param("offset", b.ty.u32()),
-                };
+    Symbol LoadFunc(const type::Type* el_ty,
+                    builtin::AddressSpace address_space,
+                    const Symbol& buffer) {
+        return utils::GetOrCreate(load_funcs, LoadStoreKey{el_ty, buffer}, [&] {
+            utils::Vector params{b.Param("offset", b.ty.u32())};
 
-                auto name = b.Sym();
+            auto name = b.Symbols().New(ctx.dst->Symbols().NameFor(buffer) + "_load");
 
-                if (auto* intrinsic = IntrinsicLoadFor(ctx.dst, address_space, el_ty)) {
-                    auto el_ast_ty = CreateASTTypeFor(ctx, el_ty);
-                    b.Func(name, params, el_ast_ty, nullptr,
-                           utils::Vector{
-                               intrinsic,
-                               b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
-                           });
-                } else if (auto* arr_ty = el_ty->As<type::Array>()) {
-                    // fn load_func(buffer : buf_ty, offset : u32) -> array<T, N> {
-                    //   var arr : array<T, N>;
-                    //   for (var i = 0u; i < array_count; i = i + 1) {
-                    //     arr[i] = el_load_func(buffer, offset + i * array_stride)
-                    //   }
-                    //   return arr;
-                    // }
-                    auto load = LoadFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
-                    auto* arr = b.Var(b.Symbols().New("arr"), CreateASTTypeFor(ctx, arr_ty));
-                    auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u));
-                    auto* for_init = b.Decl(i);
-                    auto arr_cnt = arr_ty->ConstantCount();
-                    if (TINT_UNLIKELY(!arr_cnt)) {
-                        // Non-constant counts should not be possible:
-                        // * Override-expression counts can only be applied to workgroup arrays, and
-                        //   this method only handles storage and uniform.
-                        // * Runtime-sized arrays are not loadable.
-                        TINT_ICE(Transform, b.Diagnostics())
-                            << "unexpected non-constant array count";
-                        arr_cnt = 1;
+            if (auto* intrinsic = IntrinsicLoadFor(ctx.dst, el_ty, address_space, buffer)) {
+                auto el_ast_ty = CreateASTTypeFor(ctx, el_ty);
+                b.Func(name, params, el_ast_ty, nullptr,
+                       utils::Vector{
+                           intrinsic,
+                           b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+                       });
+            } else if (auto* arr_ty = el_ty->As<type::Array>()) {
+                // fn load_func(buffer : buf_ty, offset : u32) -> array<T, N> {
+                //   var arr : array<T, N>;
+                //   for (var i = 0u; i < array_count; i = i + 1) {
+                //     arr[i] = el_load_func(buffer, offset + i * array_stride)
+                //   }
+                //   return arr;
+                // }
+                auto load = LoadFunc(arr_ty->ElemType()->UnwrapRef(), address_space, buffer);
+                auto* arr = b.Var(b.Symbols().New("arr"), CreateASTTypeFor(ctx, arr_ty));
+                auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u));
+                auto* for_init = b.Decl(i);
+                auto arr_cnt = arr_ty->ConstantCount();
+                if (TINT_UNLIKELY(!arr_cnt)) {
+                    // Non-constant counts should not be possible:
+                    // * Override-expression counts can only be applied to workgroup arrays, and
+                    //   this method only handles storage and uniform.
+                    // * Runtime-sized arrays are not loadable.
+                    TINT_ICE(Transform, b.Diagnostics()) << "unexpected non-constant array count";
+                    arr_cnt = 1;
+                }
+                auto* for_cond = b.create<ast::BinaryExpression>(
+                    ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
+                auto* for_cont = b.Assign(i, b.Add(i, 1_u));
+                auto* arr_el = b.IndexAccessor(arr, i);
+                auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
+                auto* el_val = b.Call(load, el_offset);
+                auto* for_loop =
+                    b.For(for_init, for_cond, for_cont, b.Block(b.Assign(arr_el, el_val)));
+
+                b.Func(name, params, CreateASTTypeFor(ctx, arr_ty),
+                       utils::Vector{
+                           b.Decl(arr),
+                           for_loop,
+                           b.Return(arr),
+                       });
+            } else {
+                utils::Vector<const ast::Expression*, 8> values;
+                if (auto* mat_ty = el_ty->As<type::Matrix>()) {
+                    auto* vec_ty = mat_ty->ColumnType();
+                    Symbol load = LoadFunc(vec_ty, address_space, buffer);
+                    for (uint32_t i = 0; i < mat_ty->columns(); i++) {
+                        auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
+                        values.Push(b.Call(load, offset));
                     }
-                    auto* for_cond = b.create<ast::BinaryExpression>(
-                        ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
-                    auto* for_cont = b.Assign(i, b.Add(i, 1_u));
-                    auto* arr_el = b.IndexAccessor(arr, i);
-                    auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
-                    auto* el_val = b.Call(load, "buffer", el_offset);
-                    auto* for_loop =
-                        b.For(for_init, for_cond, for_cont, b.Block(b.Assign(arr_el, el_val)));
+                } else if (auto* str = el_ty->As<sem::Struct>()) {
+                    for (auto* member : str->Members()) {
+                        auto* offset = b.Add("offset", u32(member->Offset()));
+                        Symbol load = LoadFunc(member->Type()->UnwrapRef(), address_space, buffer);
+                        values.Push(b.Call(load, offset));
+                    }
+                }
+                b.Func(name, params, CreateASTTypeFor(ctx, el_ty),
+                       utils::Vector{
+                           b.Return(b.Call(CreateASTTypeFor(ctx, el_ty), values)),
+                       });
+            }
+            return name;
+        });
+    }
 
-                    b.Func(name, params, CreateASTTypeFor(ctx, arr_ty),
-                           utils::Vector{
-                               b.Decl(arr),
-                               for_loop,
-                               b.Return(arr),
-                           });
-                } else {
-                    utils::Vector<const ast::Expression*, 8> values;
-                    if (auto* mat_ty = el_ty->As<type::Matrix>()) {
+    /// StoreFunc() returns a symbol to an intrinsic function that stores an element of type @p
+    /// el_ty to the storage buffer @p buffer. The function has the signature:
+    ///   `fn store(offset : u32, value : el_ty)`
+    /// @param el_ty the storage buffer element type
+    /// @param buffer the symbol of the storage buffer variable, owned by the target ProgramBuilder.
+    /// @return the name of the function that performs the store
+    Symbol StoreFunc(const type::Type* el_ty, const Symbol& buffer) {
+        return utils::GetOrCreate(store_funcs, LoadStoreKey{el_ty, buffer}, [&] {
+            utils::Vector params{
+                b.Param("offset", b.ty.u32()),
+                b.Param("value", CreateASTTypeFor(ctx, el_ty)),
+            };
+
+            auto name = b.Symbols().New(ctx.dst->Symbols().NameFor(buffer) + "_store");
+
+            if (auto* intrinsic = IntrinsicStoreFor(ctx.dst, el_ty, buffer)) {
+                b.Func(name, params, b.ty.void_(), nullptr,
+                       utils::Vector{
+                           intrinsic,
+                           b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+                       });
+            } else {
+                auto body = Switch<utils::Vector<const ast::Statement*, 8>>(
+                    el_ty,  //
+                    [&](const type::Array* arr_ty) {
+                        // fn store_func(buffer : buf_ty, offset : u32, value : el_ty) {
+                        //   var array = value; // No dynamic indexing on constant arrays
+                        //   for (var i = 0u; i < array_count; i = i + 1) {
+                        //     arr[i] = el_store_func(buffer, offset + i * array_stride,
+                        //     value[i])
+                        //   }
+                        //   return arr;
+                        // }
+                        auto* array = b.Var(b.Symbols().New("array"), b.Expr("value"));
+                        auto store = StoreFunc(arr_ty->ElemType()->UnwrapRef(), buffer);
+                        auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u));
+                        auto* for_init = b.Decl(i);
+                        auto arr_cnt = arr_ty->ConstantCount();
+                        if (TINT_UNLIKELY(!arr_cnt)) {
+                            // Non-constant counts should not be possible:
+                            // * Override-expression counts can only be applied to workgroup
+                            //   arrays, and this method only handles storage and uniform.
+                            // * Runtime-sized arrays are not storable.
+                            TINT_ICE(Transform, b.Diagnostics())
+                                << "unexpected non-constant array count";
+                            arr_cnt = 1;
+                        }
+                        auto* for_cond = b.create<ast::BinaryExpression>(
+                            ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
+                        auto* for_cont = b.Assign(i, b.Add(i, 1_u));
+                        auto* arr_el = b.IndexAccessor(array, i);
+                        auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
+                        auto* store_stmt = b.CallStmt(b.Call(store, el_offset, arr_el));
+                        auto* for_loop = b.For(for_init, for_cond, for_cont, b.Block(store_stmt));
+
+                        return utils::Vector{b.Decl(array), for_loop};
+                    },
+                    [&](const type::Matrix* mat_ty) {
                         auto* vec_ty = mat_ty->ColumnType();
-                        Symbol load = LoadFunc(buf_ty, vec_ty, var_user);
+                        Symbol store = StoreFunc(vec_ty, buffer);
+                        utils::Vector<const ast::Statement*, 4> stmts;
                         for (uint32_t i = 0; i < mat_ty->columns(); i++) {
                             auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
-                            values.Push(b.Call(load, "buffer", offset));
+                            auto* element = b.IndexAccessor("value", u32(i));
+                            auto* call = b.Call(store, offset, element);
+                            stmts.Push(b.CallStmt(call));
                         }
-                    } else if (auto* str = el_ty->As<sem::Struct>()) {
+                        return stmts;
+                    },
+                    [&](const sem::Struct* str) {
+                        utils::Vector<const ast::Statement*, 8> stmts;
                         for (auto* member : str->Members()) {
                             auto* offset = b.Add("offset", u32(member->Offset()));
-                            Symbol load = LoadFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
-                            values.Push(b.Call(load, "buffer", offset));
+                            auto* element = b.MemberAccessor("value", ctx.Clone(member->Name()));
+                            Symbol store = StoreFunc(member->Type()->UnwrapRef(), buffer);
+                            auto* call = b.Call(store, offset, element);
+                            stmts.Push(b.CallStmt(call));
                         }
-                    }
-                    b.Func(name, params, CreateASTTypeFor(ctx, el_ty),
-                           utils::Vector{
-                               b.Return(b.Call(CreateASTTypeFor(ctx, el_ty), values)),
-                           });
-                }
-                return name;
-            });
+                        return stmts;
+                    });
+
+                b.Func(name, params, b.ty.void_(), body);
+            }
+
+            return name;
+        });
     }
 
-    /// StoreFunc() returns a symbol to an intrinsic function that stores an
-    /// element of type `el_ty` to a storage buffer of type `buf_ty`.
-    /// The function has the signature:
-    ///   `fn store(buf : ptr<SC, buf_ty, A>, offset : u32, value : el_ty)`
-    /// @param buf_ty the storage buffer type
-    /// @param el_ty the storage buffer element type
-    /// @param var_user the variable user
-    /// @return the name of the function that performs the store
-    Symbol StoreFunc(const type::Type* buf_ty,
-                     const type::Type* el_ty,
-                     const sem::VariableUser* var_user) {
-        auto address_space = var_user->Variable()->AddressSpace();
-        auto access = var_user->Variable()->Access();
-        if (address_space != type::AddressSpace::kStorage) {
-            access = type::Access::kUndefined;
-        }
-        return utils::GetOrCreate(
-            store_funcs, LoadStoreKey{address_space, access, buf_ty, el_ty}, [&] {
-                utils::Vector params{
-                    b.Param("buffer",
-                            b.ty.pointer(CreateASTTypeFor(ctx, buf_ty), address_space, access),
-                            utils::Vector{b.Disable(ast::DisabledValidation::kFunctionParameter)}),
-                    b.Param("offset", b.ty.u32()),
-                    b.Param("value", CreateASTTypeFor(ctx, el_ty)),
-                };
-
-                auto name = b.Sym();
-
-                if (auto* intrinsic = IntrinsicStoreFor(ctx.dst, address_space, el_ty)) {
-                    b.Func(name, params, b.ty.void_(), nullptr,
-                           utils::Vector{
-                               intrinsic,
-                               b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
-                           });
-                } else {
-                    auto body = Switch<utils::Vector<const ast::Statement*, 8>>(
-                        el_ty,  //
-                        [&](const type::Array* arr_ty) {
-                            // fn store_func(buffer : buf_ty, offset : u32, value : el_ty) {
-                            //   var array = value; // No dynamic indexing on constant arrays
-                            //   for (var i = 0u; i < array_count; i = i + 1) {
-                            //     arr[i] = el_store_func(buffer, offset + i * array_stride,
-                            //     value[i])
-                            //   }
-                            //   return arr;
-                            // }
-                            auto* array = b.Var(b.Symbols().New("array"), b.Expr("value"));
-                            auto store =
-                                StoreFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
-                            auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u));
-                            auto* for_init = b.Decl(i);
-                            auto arr_cnt = arr_ty->ConstantCount();
-                            if (TINT_UNLIKELY(!arr_cnt)) {
-                                // Non-constant counts should not be possible:
-                                // * Override-expression counts can only be applied to workgroup
-                                //   arrays, and this method only handles storage and uniform.
-                                // * Runtime-sized arrays are not storable.
-                                TINT_ICE(Transform, b.Diagnostics())
-                                    << "unexpected non-constant array count";
-                                arr_cnt = 1;
-                            }
-                            auto* for_cond = b.create<ast::BinaryExpression>(
-                                ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
-                            auto* for_cont = b.Assign(i, b.Add(i, 1_u));
-                            auto* arr_el = b.IndexAccessor(array, i);
-                            auto* el_offset =
-                                b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
-                            auto* store_stmt =
-                                b.CallStmt(b.Call(store, "buffer", el_offset, arr_el));
-                            auto* for_loop =
-                                b.For(for_init, for_cond, for_cont, b.Block(store_stmt));
-
-                            return utils::Vector{b.Decl(array), for_loop};
-                        },
-                        [&](const type::Matrix* mat_ty) {
-                            auto* vec_ty = mat_ty->ColumnType();
-                            Symbol store = StoreFunc(buf_ty, vec_ty, var_user);
-                            utils::Vector<const ast::Statement*, 4> stmts;
-                            for (uint32_t i = 0; i < mat_ty->columns(); i++) {
-                                auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
-                                auto* element = b.IndexAccessor("value", u32(i));
-                                auto* call = b.Call(store, "buffer", offset, element);
-                                stmts.Push(b.CallStmt(call));
-                            }
-                            return stmts;
-                        },
-                        [&](const sem::Struct* str) {
-                            utils::Vector<const ast::Statement*, 8> stmts;
-                            for (auto* member : str->Members()) {
-                                auto* offset = b.Add("offset", u32(member->Offset()));
-                                auto* element =
-                                    b.MemberAccessor("value", ctx.Clone(member->Name()));
-                                Symbol store =
-                                    StoreFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
-                                auto* call = b.Call(store, "buffer", offset, element);
-                                stmts.Push(b.CallStmt(call));
-                            }
-                            return stmts;
-                        });
-
-                    b.Func(name, params, b.ty.void_(), body);
-                }
-
-                return name;
-            });
-    }
-
-    /// AtomicFunc() returns a symbol to an intrinsic function that performs an
-    /// atomic operation from a storage buffer of type `buf_ty`. The function has
-    /// the signature:
-    // `fn atomic_op(buf : ptr<storage, buf_ty, A>, offset : u32, ...) -> T`
-    /// @param buf_ty the storage buffer type
+    /// AtomicFunc() returns a symbol to an intrinsic function that performs an  atomic operation on
+    /// the storage buffer @p buffer. The function has the signature:
+    // `fn atomic_op(offset : u32, ...) -> T`
     /// @param el_ty the storage buffer element type
     /// @param intrinsic the atomic intrinsic
-    /// @param var_user the variable user
+    /// @param buffer the symbol of the storage buffer variable, owned by the target ProgramBuilder.
     /// @return the name of the function that performs the load
-    Symbol AtomicFunc(const type::Type* buf_ty,
-                      const type::Type* el_ty,
+    Symbol AtomicFunc(const type::Type* el_ty,
                       const sem::Builtin* intrinsic,
-                      const sem::VariableUser* var_user) {
+                      const Symbol& buffer) {
         auto op = intrinsic->Type();
-        auto address_space = var_user->Variable()->AddressSpace();
-        auto access = var_user->Variable()->Access();
-        if (address_space != type::AddressSpace::kStorage) {
-            access = type::Access::kUndefined;
-        }
-        return utils::GetOrCreate(atomic_funcs, AtomicKey{access, buf_ty, el_ty, op}, [&] {
+        return utils::GetOrCreate(atomic_funcs, AtomicKey{el_ty, op, buffer}, [&] {
             // The first parameter to all WGSL atomics is the expression to the
             // atomic. This is replaced with two parameters: the buffer and offset.
-            utils::Vector params{
-                b.Param("buffer",
-                        b.ty.pointer(CreateASTTypeFor(ctx, buf_ty), type::AddressSpace::kStorage,
-                                     access),
-                        utils::Vector{b.Disable(ast::DisabledValidation::kFunctionParameter)}),
-                b.Param("offset", b.ty.u32()),
-            };
+            utils::Vector params{b.Param("offset", b.ty.u32())};
 
             // Other parameters are copied as-is:
             for (size_t i = 1; i < intrinsic->Parameters().Length(); i++) {
@@ -692,7 +647,7 @@
                 params.Push(b.Param("param_" + std::to_string(i), ty));
             }
 
-            auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty);
+            auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty, buffer);
             if (TINT_UNLIKELY(!atomic)) {
                 TINT_ICE(Transform, b.Diagnostics())
                     << "IntrinsicAtomicFor() returned nullptr for op " << op << " and type "
@@ -720,7 +675,7 @@
                 ret_ty = CreateASTTypeFor(ctx, intrinsic->ReturnType());
             }
 
-            auto name = b.Symbols().New(std::string{"tint_"} + intrinsic->str());
+            auto name = b.Symbols().New(ctx.dst->Symbols().NameFor(buffer) + intrinsic->str());
             b.Func(name, std::move(params), ret_ty, nullptr,
                    utils::Vector{
                        atomic,
@@ -734,9 +689,10 @@
 DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid,
                                             ast::NodeID nid,
                                             Op o,
-                                            type::AddressSpace sc,
-                                            DataType ty)
-    : Base(pid, nid), op(o), address_space(sc), type(ty) {}
+                                            DataType ty,
+                                            builtin::AddressSpace as,
+                                            const Symbol& buf)
+    : Base(pid, nid), op(o), type(ty), address_space(as), buffer(buf) {}
 DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
 std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
     std::stringstream ss;
@@ -837,8 +793,9 @@
 
 const DecomposeMemoryAccess::Intrinsic* DecomposeMemoryAccess::Intrinsic::Clone(
     CloneContext* ctx) const {
+    auto buf = ctx->Clone(buffer);
     return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
-        ctx->dst->ID(), ctx->dst->AllocateNodeID(), op, address_space, type);
+        ctx->dst->ID(), ctx->dst->AllocateNodeID(), op, type, address_space, buf);
 }
 
 bool DecomposeMemoryAccess::Intrinsic::IsAtomic() const {
@@ -872,15 +829,17 @@
         if (auto* ident = node->As<ast::IdentifierExpression>()) {
             // X
             if (auto* sem_ident = sem.GetVal(ident)) {
-                if (auto* var = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
-                    if (var->Variable()->AddressSpace() == type::AddressSpace::kStorage ||
-                        var->Variable()->AddressSpace() == type::AddressSpace::kUniform) {
-                        // Variable to a storage or uniform buffer
-                        state.AddAccess(ident, {
-                                                   var,
-                                                   state.ToOffset(0u),
-                                                   var->Type()->UnwrapRef(),
-                                               });
+                if (auto* user = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
+                    if (auto* global = user->Variable()->As<sem::GlobalVariable>()) {
+                        if (global->AddressSpace() == builtin::AddressSpace::kStorage ||
+                            global->AddressSpace() == builtin::AddressSpace::kUniform) {
+                            // Variable to a storage or uniform buffer
+                            state.AddAccess(ident, {
+                                                       global,
+                                                       state.ToOffset(0u),
+                                                       global->Type()->UnwrapRef(),
+                                                   });
+                        }
                     }
                 }
             }
@@ -983,15 +942,12 @@
                     if (auto access = state.TakeAccess(call_expr->args[0])) {
                         // atomic___(X)
                         ctx.Replace(call_expr, [=, &ctx, &state] {
-                            auto* buf = access.var->Declaration();
                             auto* offset = access.offset->Build(ctx);
-                            auto* buf_ty = access.var->Type()->UnwrapRef();
                             auto* el_ty = access.type->UnwrapRef()->As<type::Atomic>()->Type();
-                            Symbol func = state.AtomicFunc(buf_ty, el_ty, builtin,
-                                                           access.var->As<sem::VariableUser>());
+                            auto buffer = ctx.Clone(access.var->Declaration()->name->symbol);
+                            Symbol func = state.AtomicFunc(el_ty, builtin, buffer);
 
-                            utils::Vector<const ast::Expression*, 8> args{
-                                ctx.dst->AddressOf(ctx.Clone(buf)), offset};
+                            utils::Vector<const ast::Expression*, 8> args{offset};
                             for (size_t i = 1; i < call_expr->args.Length(); i++) {
                                 auto* arg = call_expr->args[i];
                                 args.Push(ctx.Clone(arg));
@@ -1014,26 +970,23 @@
         }
         BufferAccess access = access_it->second;
         ctx.Replace(expr, [=, &ctx, &state] {
-            auto* buf = ctx.dst->AddressOf(ctx.CloneWithoutTransform(access.var->Declaration()));
             auto* offset = access.offset->Build(ctx);
-            auto* buf_ty = access.var->Type()->UnwrapRef();
             auto* el_ty = access.type->UnwrapRef();
-            Symbol func = state.LoadFunc(buf_ty, el_ty, access.var->As<sem::VariableUser>());
-            return ctx.dst->Call(func, buf, offset);
+            auto buffer = ctx.Clone(access.var->Declaration()->name->symbol);
+            Symbol func = state.LoadFunc(el_ty, access.var->AddressSpace(), buffer);
+            return ctx.dst->Call(func, offset);
         });
     }
 
     // And replace all storage and uniform buffer assignments with stores
     for (auto store : state.stores) {
         ctx.Replace(store.assignment, [=, &ctx, &state] {
-            auto* buf =
-                ctx.dst->AddressOf(ctx.CloneWithoutTransform((store.target.var->Declaration())));
             auto* offset = store.target.offset->Build(ctx);
-            auto* buf_ty = store.target.var->Type()->UnwrapRef();
             auto* el_ty = store.target.type->UnwrapRef();
             auto* value = store.assignment->rhs;
-            Symbol func = state.StoreFunc(buf_ty, el_ty, store.target.var->As<sem::VariableUser>());
-            auto* call = ctx.dst->Call(func, buf, offset, ctx.Clone(value));
+            auto buffer = ctx.Clone(store.target.var->Declaration()->name->symbol);
+            Symbol func = state.StoreFunc(el_ty, buffer);
+            auto* call = ctx.dst->Call(func, offset, ctx.Clone(value));
             return ctx.dst->CallStmt(call);
         });
     }
diff --git a/src/tint/transform/decompose_memory_access.h b/src/tint/transform/decompose_memory_access.h
index 3a51035..e34cd63 100644
--- a/src/tint/transform/decompose_memory_access.h
+++ b/src/tint/transform/decompose_memory_access.h
@@ -27,13 +27,12 @@
 
 namespace tint::transform {
 
-/// DecomposeMemoryAccess is a transform used to replace storage and uniform
-/// buffer accesses with a combination of load, store or atomic functions on
-/// primitive types.
+/// DecomposeMemoryAccess is a transform used to replace storage and uniform buffer accesses with a
+/// combination of load, store or atomic functions on primitive types.
 class DecomposeMemoryAccess final : public Castable<DecomposeMemoryAccess, Transform> {
   public:
-    /// Intrinsic is an InternalAttribute that's used to decorate a stub function
-    /// so that the HLSL transforms this into calls to
+    /// Intrinsic is an InternalAttribute that's used to decorate a stub function so that the HLSL
+    /// transforms this into calls to
     /// `[RW]ByteAddressBuffer.Load[N]()` or `[RW]ByteAddressBuffer.Store[N]()`,
     /// with a possible cast.
     class Intrinsic final : public Castable<Intrinsic, ast::InternalAttribute> {
@@ -79,9 +78,15 @@
         /// @param pid the identifier of the program that owns this node
         /// @param nid the unique node identifier
         /// @param o the op of the intrinsic
-        /// @param sc the address space of the buffer
-        /// @param ty the data type of the intrinsic
-        Intrinsic(ProgramID pid, ast::NodeID nid, Op o, type::AddressSpace sc, DataType ty);
+        /// @param type the data type of the intrinsic
+        /// @param address_space the address space of the buffer
+        /// @param buffer the storage or uniform buffer name
+        Intrinsic(ProgramID pid,
+                  ast::NodeID nid,
+                  Op o,
+                  DataType type,
+                  builtin::AddressSpace address_space,
+                  const Symbol& buffer);
         /// Destructor
         ~Intrinsic() override;
 
@@ -100,11 +105,14 @@
         /// The op of the intrinsic
         const Op op;
 
-        /// The address space of the buffer this intrinsic operates on
-        type::AddressSpace const address_space;
-
         /// The type of the intrinsic
         const DataType type;
+
+        /// The address space of the buffer this intrinsic operates on
+        const builtin::AddressSpace address_space;
+
+        /// The buffer name
+        const Symbol buffer;
     };
 
     /// Constructor
diff --git a/src/tint/transform/decompose_memory_access_test.cc b/src/tint/transform/decompose_memory_access_test.cc
index f0f441f..95ec9de 100644
--- a/src/tint/transform/decompose_memory_access_test.cc
+++ b/src/tint/transform/decompose_memory_access_test.cc
@@ -180,179 +180,179 @@
 @group(0) @binding(0) var<storage, read_write> sb : SB;
 
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load(offset : u32) -> f32
 
 @internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
+fn sb_load_1(offset : u32) -> i32
 
 @internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
+fn sb_load_2(offset : u32) -> u32
 
 @internal(intrinsic_load_storage_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f16
+fn sb_load_3(offset : u32) -> f16
 
 @internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f32>
+fn sb_load_4(offset : u32) -> vec2<f32>
 
 @internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<i32>
+fn sb_load_5(offset : u32) -> vec2<i32>
 
 @internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<u32>
+fn sb_load_6(offset : u32) -> vec2<u32>
 
 @internal(intrinsic_load_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f16>
+fn sb_load_7(offset : u32) -> vec2<f16>
 
 @internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f32>
+fn sb_load_8(offset : u32) -> vec3<f32>
 
 @internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<i32>
+fn sb_load_9(offset : u32) -> vec3<i32>
 
 @internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<u32>
+fn sb_load_10(offset : u32) -> vec3<u32>
 
 @internal(intrinsic_load_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f16>
+fn sb_load_11(offset : u32) -> vec3<f16>
 
 @internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f32>
+fn sb_load_12(offset : u32) -> vec4<f32>
 
 @internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<i32>
+fn sb_load_13(offset : u32) -> vec4<i32>
 
 @internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<u32>
+fn sb_load_14(offset : u32) -> vec4<u32>
 
 @internal(intrinsic_load_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f16>
+fn sb_load_15(offset : u32) -> vec4<f16>
 
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f32> {
-  return mat2x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)));
+fn sb_load_16(offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)));
 }
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f32> {
-  return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
+fn sb_load_17(offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)));
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f32> {
-  return mat2x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)));
+fn sb_load_18(offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)));
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f32> {
-  return mat3x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)));
+fn sb_load_19(offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)), sb_load_4((offset + 16u)));
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_load_20(offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)), sb_load_8((offset + 32u)));
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f32> {
-  return mat3x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)));
+fn sb_load_21(offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)), sb_load_12((offset + 32u)));
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f32> {
-  return mat4x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)), tint_symbol_4(buffer, (offset + 24u)));
+fn sb_load_22(offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)), sb_load_4((offset + 16u)), sb_load_4((offset + 24u)));
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_load_23(offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)), sb_load_8((offset + 32u)), sb_load_8((offset + 48u)));
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f32> {
-  return mat4x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)), tint_symbol_12(buffer, (offset + 48u)));
+fn sb_load_24(offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)), sb_load_12((offset + 32u)), sb_load_12((offset + 48u)));
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f16> {
-  return mat2x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)));
+fn sb_load_25(offset : u32) -> mat2x2<f16> {
+  return mat2x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)));
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f16> {
-  return mat2x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)));
+fn sb_load_26(offset : u32) -> mat2x3<f16> {
+  return mat2x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)));
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f16> {
-  return mat2x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)));
+fn sb_load_27(offset : u32) -> mat2x4<f16> {
+  return mat2x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)));
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f16> {
-  return mat3x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)), tint_symbol_7(buffer, (offset + 8u)));
+fn sb_load_28(offset : u32) -> mat3x2<f16> {
+  return mat3x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)), sb_load_7((offset + 8u)));
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f16> {
-  return mat3x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)), tint_symbol_11(buffer, (offset + 16u)));
+fn sb_load_29(offset : u32) -> mat3x3<f16> {
+  return mat3x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)), sb_load_11((offset + 16u)));
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f16> {
-  return mat3x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)), tint_symbol_15(buffer, (offset + 16u)));
+fn sb_load_30(offset : u32) -> mat3x4<f16> {
+  return mat3x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)), sb_load_15((offset + 16u)));
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f16> {
-  return mat4x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)), tint_symbol_7(buffer, (offset + 8u)), tint_symbol_7(buffer, (offset + 12u)));
+fn sb_load_31(offset : u32) -> mat4x2<f16> {
+  return mat4x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)), sb_load_7((offset + 8u)), sb_load_7((offset + 12u)));
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f16> {
-  return mat4x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 24u)));
+fn sb_load_32(offset : u32) -> mat4x3<f16> {
+  return mat4x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)), sb_load_11((offset + 16u)), sb_load_11((offset + 24u)));
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f16> {
-  return mat4x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)), tint_symbol_15(buffer, (offset + 16u)), tint_symbol_15(buffer, (offset + 24u)));
+fn sb_load_33(offset : u32) -> mat4x4<f16> {
+  return mat4x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)), sb_load_15((offset + 16u)), sb_load_15((offset + 24u)));
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f32>, 2u> {
+fn sb_load_34(offset : u32) -> array<vec3<f32>, 2u> {
   var arr : array<vec3<f32>, 2u>;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    arr[i] = tint_symbol_8(buffer, (offset + (i * 16u)));
+    arr[i] = sb_load_8((offset + (i * 16u)));
   }
   return arr;
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f16>, 2u> {
+fn sb_load_35(offset : u32) -> array<vec3<f16>, 2u> {
   var arr_1 : array<vec3<f16>, 2u>;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    arr_1[i_1] = tint_symbol_11(buffer, (offset + (i_1 * 8u)));
+    arr_1[i_1] = sb_load_11((offset + (i_1 * 8u)));
   }
   return arr_1;
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  var scalar_f32 : f32 = tint_symbol(&(sb), 0u);
-  var scalar_i32 : i32 = tint_symbol_1(&(sb), 4u);
-  var scalar_u32 : u32 = tint_symbol_2(&(sb), 8u);
-  var scalar_f16 : f16 = tint_symbol_3(&(sb), 12u);
-  var vec2_f32 : vec2<f32> = tint_symbol_4(&(sb), 16u);
-  var vec2_i32 : vec2<i32> = tint_symbol_5(&(sb), 24u);
-  var vec2_u32 : vec2<u32> = tint_symbol_6(&(sb), 32u);
-  var vec2_f16 : vec2<f16> = tint_symbol_7(&(sb), 40u);
-  var vec3_f32 : vec3<f32> = tint_symbol_8(&(sb), 48u);
-  var vec3_i32 : vec3<i32> = tint_symbol_9(&(sb), 64u);
-  var vec3_u32 : vec3<u32> = tint_symbol_10(&(sb), 80u);
-  var vec3_f16 : vec3<f16> = tint_symbol_11(&(sb), 96u);
-  var vec4_f32 : vec4<f32> = tint_symbol_12(&(sb), 112u);
-  var vec4_i32 : vec4<i32> = tint_symbol_13(&(sb), 128u);
-  var vec4_u32 : vec4<u32> = tint_symbol_14(&(sb), 144u);
-  var vec4_f16 : vec4<f16> = tint_symbol_15(&(sb), 160u);
-  var mat2x2_f32 : mat2x2<f32> = tint_symbol_16(&(sb), 168u);
-  var mat2x3_f32 : mat2x3<f32> = tint_symbol_17(&(sb), 192u);
-  var mat2x4_f32 : mat2x4<f32> = tint_symbol_18(&(sb), 224u);
-  var mat3x2_f32 : mat3x2<f32> = tint_symbol_19(&(sb), 256u);
-  var mat3x3_f32 : mat3x3<f32> = tint_symbol_20(&(sb), 288u);
-  var mat3x4_f32 : mat3x4<f32> = tint_symbol_21(&(sb), 336u);
-  var mat4x2_f32 : mat4x2<f32> = tint_symbol_22(&(sb), 384u);
-  var mat4x3_f32 : mat4x3<f32> = tint_symbol_23(&(sb), 416u);
-  var mat4x4_f32 : mat4x4<f32> = tint_symbol_24(&(sb), 480u);
-  var mat2x2_f16 : mat2x2<f16> = tint_symbol_25(&(sb), 544u);
-  var mat2x3_f16 : mat2x3<f16> = tint_symbol_26(&(sb), 552u);
-  var mat2x4_f16 : mat2x4<f16> = tint_symbol_27(&(sb), 568u);
-  var mat3x2_f16 : mat3x2<f16> = tint_symbol_28(&(sb), 584u);
-  var mat3x3_f16 : mat3x3<f16> = tint_symbol_29(&(sb), 600u);
-  var mat3x4_f16 : mat3x4<f16> = tint_symbol_30(&(sb), 624u);
-  var mat4x2_f16 : mat4x2<f16> = tint_symbol_31(&(sb), 648u);
-  var mat4x3_f16 : mat4x3<f16> = tint_symbol_32(&(sb), 664u);
-  var mat4x4_f16 : mat4x4<f16> = tint_symbol_33(&(sb), 696u);
-  var arr2_vec3_f32 : array<vec3<f32>, 2> = tint_symbol_34(&(sb), 736u);
-  var arr2_vec3_f16 : array<vec3<f16>, 2> = tint_symbol_35(&(sb), 768u);
+  var scalar_f32 : f32 = sb_load(0u);
+  var scalar_i32 : i32 = sb_load_1(4u);
+  var scalar_u32 : u32 = sb_load_2(8u);
+  var scalar_f16 : f16 = sb_load_3(12u);
+  var vec2_f32 : vec2<f32> = sb_load_4(16u);
+  var vec2_i32 : vec2<i32> = sb_load_5(24u);
+  var vec2_u32 : vec2<u32> = sb_load_6(32u);
+  var vec2_f16 : vec2<f16> = sb_load_7(40u);
+  var vec3_f32 : vec3<f32> = sb_load_8(48u);
+  var vec3_i32 : vec3<i32> = sb_load_9(64u);
+  var vec3_u32 : vec3<u32> = sb_load_10(80u);
+  var vec3_f16 : vec3<f16> = sb_load_11(96u);
+  var vec4_f32 : vec4<f32> = sb_load_12(112u);
+  var vec4_i32 : vec4<i32> = sb_load_13(128u);
+  var vec4_u32 : vec4<u32> = sb_load_14(144u);
+  var vec4_f16 : vec4<f16> = sb_load_15(160u);
+  var mat2x2_f32 : mat2x2<f32> = sb_load_16(168u);
+  var mat2x3_f32 : mat2x3<f32> = sb_load_17(192u);
+  var mat2x4_f32 : mat2x4<f32> = sb_load_18(224u);
+  var mat3x2_f32 : mat3x2<f32> = sb_load_19(256u);
+  var mat3x3_f32 : mat3x3<f32> = sb_load_20(288u);
+  var mat3x4_f32 : mat3x4<f32> = sb_load_21(336u);
+  var mat4x2_f32 : mat4x2<f32> = sb_load_22(384u);
+  var mat4x3_f32 : mat4x3<f32> = sb_load_23(416u);
+  var mat4x4_f32 : mat4x4<f32> = sb_load_24(480u);
+  var mat2x2_f16 : mat2x2<f16> = sb_load_25(544u);
+  var mat2x3_f16 : mat2x3<f16> = sb_load_26(552u);
+  var mat2x4_f16 : mat2x4<f16> = sb_load_27(568u);
+  var mat3x2_f16 : mat3x2<f16> = sb_load_28(584u);
+  var mat3x3_f16 : mat3x3<f16> = sb_load_29(600u);
+  var mat3x4_f16 : mat3x4<f16> = sb_load_30(624u);
+  var mat4x2_f16 : mat4x2<f16> = sb_load_31(648u);
+  var mat4x3_f16 : mat4x3<f16> = sb_load_32(664u);
+  var mat4x4_f16 : mat4x4<f16> = sb_load_33(696u);
+  var arr2_vec3_f32 : array<vec3<f32>, 2> = sb_load_34(736u);
+  var arr2_vec3_f16 : array<vec3<f16>, 2> = sb_load_35(768u);
 }
 )";
 
@@ -451,179 +451,179 @@
 enable f16;
 
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load(offset : u32) -> f32
 
 @internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
+fn sb_load_1(offset : u32) -> i32
 
 @internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
+fn sb_load_2(offset : u32) -> u32
 
 @internal(intrinsic_load_storage_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f16
+fn sb_load_3(offset : u32) -> f16
 
 @internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f32>
+fn sb_load_4(offset : u32) -> vec2<f32>
 
 @internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<i32>
+fn sb_load_5(offset : u32) -> vec2<i32>
 
 @internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<u32>
+fn sb_load_6(offset : u32) -> vec2<u32>
 
 @internal(intrinsic_load_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f16>
+fn sb_load_7(offset : u32) -> vec2<f16>
 
 @internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f32>
+fn sb_load_8(offset : u32) -> vec3<f32>
 
 @internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<i32>
+fn sb_load_9(offset : u32) -> vec3<i32>
 
 @internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<u32>
+fn sb_load_10(offset : u32) -> vec3<u32>
 
 @internal(intrinsic_load_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f16>
+fn sb_load_11(offset : u32) -> vec3<f16>
 
 @internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f32>
+fn sb_load_12(offset : u32) -> vec4<f32>
 
 @internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<i32>
+fn sb_load_13(offset : u32) -> vec4<i32>
 
 @internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<u32>
+fn sb_load_14(offset : u32) -> vec4<u32>
 
 @internal(intrinsic_load_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f16>
+fn sb_load_15(offset : u32) -> vec4<f16>
 
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f32> {
-  return mat2x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)));
+fn sb_load_16(offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)));
 }
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f32> {
-  return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
+fn sb_load_17(offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)));
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f32> {
-  return mat2x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)));
+fn sb_load_18(offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)));
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f32> {
-  return mat3x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)));
+fn sb_load_19(offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)), sb_load_4((offset + 16u)));
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_load_20(offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)), sb_load_8((offset + 32u)));
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f32> {
-  return mat3x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)));
+fn sb_load_21(offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)), sb_load_12((offset + 32u)));
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f32> {
-  return mat4x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)), tint_symbol_4(buffer, (offset + 24u)));
+fn sb_load_22(offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)), sb_load_4((offset + 16u)), sb_load_4((offset + 24u)));
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_load_23(offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)), sb_load_8((offset + 32u)), sb_load_8((offset + 48u)));
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f32> {
-  return mat4x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)), tint_symbol_12(buffer, (offset + 48u)));
+fn sb_load_24(offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)), sb_load_12((offset + 32u)), sb_load_12((offset + 48u)));
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f16> {
-  return mat2x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)));
+fn sb_load_25(offset : u32) -> mat2x2<f16> {
+  return mat2x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)));
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f16> {
-  return mat2x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)));
+fn sb_load_26(offset : u32) -> mat2x3<f16> {
+  return mat2x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)));
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f16> {
-  return mat2x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)));
+fn sb_load_27(offset : u32) -> mat2x4<f16> {
+  return mat2x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)));
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f16> {
-  return mat3x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)), tint_symbol_7(buffer, (offset + 8u)));
+fn sb_load_28(offset : u32) -> mat3x2<f16> {
+  return mat3x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)), sb_load_7((offset + 8u)));
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f16> {
-  return mat3x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)), tint_symbol_11(buffer, (offset + 16u)));
+fn sb_load_29(offset : u32) -> mat3x3<f16> {
+  return mat3x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)), sb_load_11((offset + 16u)));
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f16> {
-  return mat3x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)), tint_symbol_15(buffer, (offset + 16u)));
+fn sb_load_30(offset : u32) -> mat3x4<f16> {
+  return mat3x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)), sb_load_15((offset + 16u)));
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f16> {
-  return mat4x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)), tint_symbol_7(buffer, (offset + 8u)), tint_symbol_7(buffer, (offset + 12u)));
+fn sb_load_31(offset : u32) -> mat4x2<f16> {
+  return mat4x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)), sb_load_7((offset + 8u)), sb_load_7((offset + 12u)));
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f16> {
-  return mat4x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 24u)));
+fn sb_load_32(offset : u32) -> mat4x3<f16> {
+  return mat4x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)), sb_load_11((offset + 16u)), sb_load_11((offset + 24u)));
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f16> {
-  return mat4x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)), tint_symbol_15(buffer, (offset + 16u)), tint_symbol_15(buffer, (offset + 24u)));
+fn sb_load_33(offset : u32) -> mat4x4<f16> {
+  return mat4x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)), sb_load_15((offset + 16u)), sb_load_15((offset + 24u)));
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f32>, 2u> {
+fn sb_load_34(offset : u32) -> array<vec3<f32>, 2u> {
   var arr : array<vec3<f32>, 2u>;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    arr[i] = tint_symbol_8(buffer, (offset + (i * 16u)));
+    arr[i] = sb_load_8((offset + (i * 16u)));
   }
   return arr;
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f16>, 2u> {
+fn sb_load_35(offset : u32) -> array<vec3<f16>, 2u> {
   var arr_1 : array<vec3<f16>, 2u>;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    arr_1[i_1] = tint_symbol_11(buffer, (offset + (i_1 * 8u)));
+    arr_1[i_1] = sb_load_11((offset + (i_1 * 8u)));
   }
   return arr_1;
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  var scalar_f32 : f32 = tint_symbol(&(sb), 0u);
-  var scalar_i32 : i32 = tint_symbol_1(&(sb), 4u);
-  var scalar_u32 : u32 = tint_symbol_2(&(sb), 8u);
-  var scalar_f16 : f16 = tint_symbol_3(&(sb), 12u);
-  var vec2_f32 : vec2<f32> = tint_symbol_4(&(sb), 16u);
-  var vec2_i32 : vec2<i32> = tint_symbol_5(&(sb), 24u);
-  var vec2_u32 : vec2<u32> = tint_symbol_6(&(sb), 32u);
-  var vec2_f16 : vec2<f16> = tint_symbol_7(&(sb), 40u);
-  var vec3_f32 : vec3<f32> = tint_symbol_8(&(sb), 48u);
-  var vec3_i32 : vec3<i32> = tint_symbol_9(&(sb), 64u);
-  var vec3_u32 : vec3<u32> = tint_symbol_10(&(sb), 80u);
-  var vec3_f16 : vec3<f16> = tint_symbol_11(&(sb), 96u);
-  var vec4_f32 : vec4<f32> = tint_symbol_12(&(sb), 112u);
-  var vec4_i32 : vec4<i32> = tint_symbol_13(&(sb), 128u);
-  var vec4_u32 : vec4<u32> = tint_symbol_14(&(sb), 144u);
-  var vec4_f16 : vec4<f16> = tint_symbol_15(&(sb), 160u);
-  var mat2x2_f32 : mat2x2<f32> = tint_symbol_16(&(sb), 168u);
-  var mat2x3_f32 : mat2x3<f32> = tint_symbol_17(&(sb), 192u);
-  var mat2x4_f32 : mat2x4<f32> = tint_symbol_18(&(sb), 224u);
-  var mat3x2_f32 : mat3x2<f32> = tint_symbol_19(&(sb), 256u);
-  var mat3x3_f32 : mat3x3<f32> = tint_symbol_20(&(sb), 288u);
-  var mat3x4_f32 : mat3x4<f32> = tint_symbol_21(&(sb), 336u);
-  var mat4x2_f32 : mat4x2<f32> = tint_symbol_22(&(sb), 384u);
-  var mat4x3_f32 : mat4x3<f32> = tint_symbol_23(&(sb), 416u);
-  var mat4x4_f32 : mat4x4<f32> = tint_symbol_24(&(sb), 480u);
-  var mat2x2_f16 : mat2x2<f16> = tint_symbol_25(&(sb), 544u);
-  var mat2x3_f16 : mat2x3<f16> = tint_symbol_26(&(sb), 552u);
-  var mat2x4_f16 : mat2x4<f16> = tint_symbol_27(&(sb), 568u);
-  var mat3x2_f16 : mat3x2<f16> = tint_symbol_28(&(sb), 584u);
-  var mat3x3_f16 : mat3x3<f16> = tint_symbol_29(&(sb), 600u);
-  var mat3x4_f16 : mat3x4<f16> = tint_symbol_30(&(sb), 624u);
-  var mat4x2_f16 : mat4x2<f16> = tint_symbol_31(&(sb), 648u);
-  var mat4x3_f16 : mat4x3<f16> = tint_symbol_32(&(sb), 664u);
-  var mat4x4_f16 : mat4x4<f16> = tint_symbol_33(&(sb), 696u);
-  var arr2_vec3_f32 : array<vec3<f32>, 2> = tint_symbol_34(&(sb), 736u);
-  var arr2_vec3_f16 : array<vec3<f16>, 2> = tint_symbol_35(&(sb), 768u);
+  var scalar_f32 : f32 = sb_load(0u);
+  var scalar_i32 : i32 = sb_load_1(4u);
+  var scalar_u32 : u32 = sb_load_2(8u);
+  var scalar_f16 : f16 = sb_load_3(12u);
+  var vec2_f32 : vec2<f32> = sb_load_4(16u);
+  var vec2_i32 : vec2<i32> = sb_load_5(24u);
+  var vec2_u32 : vec2<u32> = sb_load_6(32u);
+  var vec2_f16 : vec2<f16> = sb_load_7(40u);
+  var vec3_f32 : vec3<f32> = sb_load_8(48u);
+  var vec3_i32 : vec3<i32> = sb_load_9(64u);
+  var vec3_u32 : vec3<u32> = sb_load_10(80u);
+  var vec3_f16 : vec3<f16> = sb_load_11(96u);
+  var vec4_f32 : vec4<f32> = sb_load_12(112u);
+  var vec4_i32 : vec4<i32> = sb_load_13(128u);
+  var vec4_u32 : vec4<u32> = sb_load_14(144u);
+  var vec4_f16 : vec4<f16> = sb_load_15(160u);
+  var mat2x2_f32 : mat2x2<f32> = sb_load_16(168u);
+  var mat2x3_f32 : mat2x3<f32> = sb_load_17(192u);
+  var mat2x4_f32 : mat2x4<f32> = sb_load_18(224u);
+  var mat3x2_f32 : mat3x2<f32> = sb_load_19(256u);
+  var mat3x3_f32 : mat3x3<f32> = sb_load_20(288u);
+  var mat3x4_f32 : mat3x4<f32> = sb_load_21(336u);
+  var mat4x2_f32 : mat4x2<f32> = sb_load_22(384u);
+  var mat4x3_f32 : mat4x3<f32> = sb_load_23(416u);
+  var mat4x4_f32 : mat4x4<f32> = sb_load_24(480u);
+  var mat2x2_f16 : mat2x2<f16> = sb_load_25(544u);
+  var mat2x3_f16 : mat2x3<f16> = sb_load_26(552u);
+  var mat2x4_f16 : mat2x4<f16> = sb_load_27(568u);
+  var mat3x2_f16 : mat3x2<f16> = sb_load_28(584u);
+  var mat3x3_f16 : mat3x3<f16> = sb_load_29(600u);
+  var mat3x4_f16 : mat3x4<f16> = sb_load_30(624u);
+  var mat4x2_f16 : mat4x2<f16> = sb_load_31(648u);
+  var mat4x3_f16 : mat4x3<f16> = sb_load_32(664u);
+  var mat4x4_f16 : mat4x4<f16> = sb_load_33(696u);
+  var arr2_vec3_f32 : array<vec3<f32>, 2> = sb_load_34(736u);
+  var arr2_vec3_f16 : array<vec3<f16>, 2> = sb_load_35(768u);
 }
 
 @group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -804,179 +804,179 @@
 @group(0) @binding(0) var<uniform> ub : UB;
 
 @internal(intrinsic_load_uniform_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> f32
+fn ub_load(offset : u32) -> f32
 
 @internal(intrinsic_load_uniform_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> i32
+fn ub_load_1(offset : u32) -> i32
 
 @internal(intrinsic_load_uniform_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> u32
+fn ub_load_2(offset : u32) -> u32
 
 @internal(intrinsic_load_uniform_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> f16
+fn ub_load_3(offset : u32) -> f16
 
 @internal(intrinsic_load_uniform_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec2<f32>
+fn ub_load_4(offset : u32) -> vec2<f32>
 
 @internal(intrinsic_load_uniform_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec2<i32>
+fn ub_load_5(offset : u32) -> vec2<i32>
 
 @internal(intrinsic_load_uniform_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec2<u32>
+fn ub_load_6(offset : u32) -> vec2<u32>
 
 @internal(intrinsic_load_uniform_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec2<f16>
+fn ub_load_7(offset : u32) -> vec2<f16>
 
 @internal(intrinsic_load_uniform_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec3<f32>
+fn ub_load_8(offset : u32) -> vec3<f32>
 
 @internal(intrinsic_load_uniform_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec3<i32>
+fn ub_load_9(offset : u32) -> vec3<i32>
 
 @internal(intrinsic_load_uniform_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec3<u32>
+fn ub_load_10(offset : u32) -> vec3<u32>
 
 @internal(intrinsic_load_uniform_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec3<f16>
+fn ub_load_11(offset : u32) -> vec3<f16>
 
 @internal(intrinsic_load_uniform_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec4<f32>
+fn ub_load_12(offset : u32) -> vec4<f32>
 
 @internal(intrinsic_load_uniform_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec4<i32>
+fn ub_load_13(offset : u32) -> vec4<i32>
 
 @internal(intrinsic_load_uniform_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec4<u32>
+fn ub_load_14(offset : u32) -> vec4<u32>
 
 @internal(intrinsic_load_uniform_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec4<f16>
+fn ub_load_15(offset : u32) -> vec4<f16>
 
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x2<f32> {
-  return mat2x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)));
+fn ub_load_16(offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)));
 }
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x3<f32> {
-  return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
+fn ub_load_17(offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)));
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x4<f32> {
-  return mat2x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)));
+fn ub_load_18(offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)));
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x2<f32> {
-  return mat3x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)));
+fn ub_load_19(offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)), ub_load_4((offset + 16u)));
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, 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 ub_load_20(offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)), ub_load_8((offset + 32u)));
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x4<f32> {
-  return mat3x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)));
+fn ub_load_21(offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)), ub_load_12((offset + 32u)));
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x2<f32> {
-  return mat4x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)), tint_symbol_4(buffer, (offset + 24u)));
+fn ub_load_22(offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)), ub_load_4((offset + 16u)), ub_load_4((offset + 24u)));
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, 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 ub_load_23(offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)), ub_load_8((offset + 32u)), ub_load_8((offset + 48u)));
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x4<f32> {
-  return mat4x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)), tint_symbol_12(buffer, (offset + 48u)));
+fn ub_load_24(offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)), ub_load_12((offset + 32u)), ub_load_12((offset + 48u)));
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x2<f16> {
-  return mat2x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)));
+fn ub_load_25(offset : u32) -> mat2x2<f16> {
+  return mat2x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)));
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x3<f16> {
-  return mat2x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)));
+fn ub_load_26(offset : u32) -> mat2x3<f16> {
+  return mat2x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)));
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x4<f16> {
-  return mat2x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)));
+fn ub_load_27(offset : u32) -> mat2x4<f16> {
+  return mat2x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)));
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x2<f16> {
-  return mat3x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)), tint_symbol_7(buffer, (offset + 8u)));
+fn ub_load_28(offset : u32) -> mat3x2<f16> {
+  return mat3x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)), ub_load_7((offset + 8u)));
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x3<f16> {
-  return mat3x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)), tint_symbol_11(buffer, (offset + 16u)));
+fn ub_load_29(offset : u32) -> mat3x3<f16> {
+  return mat3x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)), ub_load_11((offset + 16u)));
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x4<f16> {
-  return mat3x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)), tint_symbol_15(buffer, (offset + 16u)));
+fn ub_load_30(offset : u32) -> mat3x4<f16> {
+  return mat3x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)), ub_load_15((offset + 16u)));
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x2<f16> {
-  return mat4x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)), tint_symbol_7(buffer, (offset + 8u)), tint_symbol_7(buffer, (offset + 12u)));
+fn ub_load_31(offset : u32) -> mat4x2<f16> {
+  return mat4x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)), ub_load_7((offset + 8u)), ub_load_7((offset + 12u)));
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x3<f16> {
-  return mat4x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 24u)));
+fn ub_load_32(offset : u32) -> mat4x3<f16> {
+  return mat4x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)), ub_load_11((offset + 16u)), ub_load_11((offset + 24u)));
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x4<f16> {
-  return mat4x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)), tint_symbol_15(buffer, (offset + 16u)), tint_symbol_15(buffer, (offset + 24u)));
+fn ub_load_33(offset : u32) -> mat4x4<f16> {
+  return mat4x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)), ub_load_15((offset + 16u)), ub_load_15((offset + 24u)));
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> array<vec3<f32>, 2u> {
+fn ub_load_34(offset : u32) -> array<vec3<f32>, 2u> {
   var arr : array<vec3<f32>, 2u>;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    arr[i] = tint_symbol_8(buffer, (offset + (i * 16u)));
+    arr[i] = ub_load_8((offset + (i * 16u)));
   }
   return arr;
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> array<mat4x2<f16>, 2u> {
+fn ub_load_35(offset : u32) -> array<mat4x2<f16>, 2u> {
   var arr_1 : array<mat4x2<f16>, 2u>;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    arr_1[i_1] = tint_symbol_31(buffer, (offset + (i_1 * 16u)));
+    arr_1[i_1] = ub_load_31((offset + (i_1 * 16u)));
   }
   return arr_1;
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  var scalar_f32 : f32 = tint_symbol(&(ub), 0u);
-  var scalar_i32 : i32 = tint_symbol_1(&(ub), 4u);
-  var scalar_u32 : u32 = tint_symbol_2(&(ub), 8u);
-  var scalar_f16 : f16 = tint_symbol_3(&(ub), 12u);
-  var vec2_f32 : vec2<f32> = tint_symbol_4(&(ub), 16u);
-  var vec2_i32 : vec2<i32> = tint_symbol_5(&(ub), 24u);
-  var vec2_u32 : vec2<u32> = tint_symbol_6(&(ub), 32u);
-  var vec2_f16 : vec2<f16> = tint_symbol_7(&(ub), 40u);
-  var vec3_f32 : vec3<f32> = tint_symbol_8(&(ub), 48u);
-  var vec3_i32 : vec3<i32> = tint_symbol_9(&(ub), 64u);
-  var vec3_u32 : vec3<u32> = tint_symbol_10(&(ub), 80u);
-  var vec3_f16 : vec3<f16> = tint_symbol_11(&(ub), 96u);
-  var vec4_f32 : vec4<f32> = tint_symbol_12(&(ub), 112u);
-  var vec4_i32 : vec4<i32> = tint_symbol_13(&(ub), 128u);
-  var vec4_u32 : vec4<u32> = tint_symbol_14(&(ub), 144u);
-  var vec4_f16 : vec4<f16> = tint_symbol_15(&(ub), 160u);
-  var mat2x2_f32 : mat2x2<f32> = tint_symbol_16(&(ub), 168u);
-  var mat2x3_f32 : mat2x3<f32> = tint_symbol_17(&(ub), 192u);
-  var mat2x4_f32 : mat2x4<f32> = tint_symbol_18(&(ub), 224u);
-  var mat3x2_f32 : mat3x2<f32> = tint_symbol_19(&(ub), 256u);
-  var mat3x3_f32 : mat3x3<f32> = tint_symbol_20(&(ub), 288u);
-  var mat3x4_f32 : mat3x4<f32> = tint_symbol_21(&(ub), 336u);
-  var mat4x2_f32 : mat4x2<f32> = tint_symbol_22(&(ub), 384u);
-  var mat4x3_f32 : mat4x3<f32> = tint_symbol_23(&(ub), 416u);
-  var mat4x4_f32 : mat4x4<f32> = tint_symbol_24(&(ub), 480u);
-  var mat2x2_f16 : mat2x2<f16> = tint_symbol_25(&(ub), 544u);
-  var mat2x3_f16 : mat2x3<f16> = tint_symbol_26(&(ub), 552u);
-  var mat2x4_f16 : mat2x4<f16> = tint_symbol_27(&(ub), 568u);
-  var mat3x2_f16 : mat3x2<f16> = tint_symbol_28(&(ub), 584u);
-  var mat3x3_f16 : mat3x3<f16> = tint_symbol_29(&(ub), 600u);
-  var mat3x4_f16 : mat3x4<f16> = tint_symbol_30(&(ub), 624u);
-  var mat4x2_f16 : mat4x2<f16> = tint_symbol_31(&(ub), 648u);
-  var mat4x3_f16 : mat4x3<f16> = tint_symbol_32(&(ub), 664u);
-  var mat4x4_f16 : mat4x4<f16> = tint_symbol_33(&(ub), 696u);
-  var arr2_vec3_f32 : array<vec3<f32>, 2> = tint_symbol_34(&(ub), 736u);
-  var arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = tint_symbol_35(&(ub), 768u);
+  var scalar_f32 : f32 = ub_load(0u);
+  var scalar_i32 : i32 = ub_load_1(4u);
+  var scalar_u32 : u32 = ub_load_2(8u);
+  var scalar_f16 : f16 = ub_load_3(12u);
+  var vec2_f32 : vec2<f32> = ub_load_4(16u);
+  var vec2_i32 : vec2<i32> = ub_load_5(24u);
+  var vec2_u32 : vec2<u32> = ub_load_6(32u);
+  var vec2_f16 : vec2<f16> = ub_load_7(40u);
+  var vec3_f32 : vec3<f32> = ub_load_8(48u);
+  var vec3_i32 : vec3<i32> = ub_load_9(64u);
+  var vec3_u32 : vec3<u32> = ub_load_10(80u);
+  var vec3_f16 : vec3<f16> = ub_load_11(96u);
+  var vec4_f32 : vec4<f32> = ub_load_12(112u);
+  var vec4_i32 : vec4<i32> = ub_load_13(128u);
+  var vec4_u32 : vec4<u32> = ub_load_14(144u);
+  var vec4_f16 : vec4<f16> = ub_load_15(160u);
+  var mat2x2_f32 : mat2x2<f32> = ub_load_16(168u);
+  var mat2x3_f32 : mat2x3<f32> = ub_load_17(192u);
+  var mat2x4_f32 : mat2x4<f32> = ub_load_18(224u);
+  var mat3x2_f32 : mat3x2<f32> = ub_load_19(256u);
+  var mat3x3_f32 : mat3x3<f32> = ub_load_20(288u);
+  var mat3x4_f32 : mat3x4<f32> = ub_load_21(336u);
+  var mat4x2_f32 : mat4x2<f32> = ub_load_22(384u);
+  var mat4x3_f32 : mat4x3<f32> = ub_load_23(416u);
+  var mat4x4_f32 : mat4x4<f32> = ub_load_24(480u);
+  var mat2x2_f16 : mat2x2<f16> = ub_load_25(544u);
+  var mat2x3_f16 : mat2x3<f16> = ub_load_26(552u);
+  var mat2x4_f16 : mat2x4<f16> = ub_load_27(568u);
+  var mat3x2_f16 : mat3x2<f16> = ub_load_28(584u);
+  var mat3x3_f16 : mat3x3<f16> = ub_load_29(600u);
+  var mat3x4_f16 : mat3x4<f16> = ub_load_30(624u);
+  var mat4x2_f16 : mat4x2<f16> = ub_load_31(648u);
+  var mat4x3_f16 : mat4x3<f16> = ub_load_32(664u);
+  var mat4x4_f16 : mat4x4<f16> = ub_load_33(696u);
+  var arr2_vec3_f32 : array<vec3<f32>, 2> = ub_load_34(736u);
+  var arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = ub_load_35(768u);
 }
 )";
 
@@ -1075,179 +1075,179 @@
 enable f16;
 
 @internal(intrinsic_load_uniform_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> f32
+fn ub_load(offset : u32) -> f32
 
 @internal(intrinsic_load_uniform_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> i32
+fn ub_load_1(offset : u32) -> i32
 
 @internal(intrinsic_load_uniform_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> u32
+fn ub_load_2(offset : u32) -> u32
 
 @internal(intrinsic_load_uniform_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> f16
+fn ub_load_3(offset : u32) -> f16
 
 @internal(intrinsic_load_uniform_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec2<f32>
+fn ub_load_4(offset : u32) -> vec2<f32>
 
 @internal(intrinsic_load_uniform_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec2<i32>
+fn ub_load_5(offset : u32) -> vec2<i32>
 
 @internal(intrinsic_load_uniform_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec2<u32>
+fn ub_load_6(offset : u32) -> vec2<u32>
 
 @internal(intrinsic_load_uniform_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec2<f16>
+fn ub_load_7(offset : u32) -> vec2<f16>
 
 @internal(intrinsic_load_uniform_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec3<f32>
+fn ub_load_8(offset : u32) -> vec3<f32>
 
 @internal(intrinsic_load_uniform_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec3<i32>
+fn ub_load_9(offset : u32) -> vec3<i32>
 
 @internal(intrinsic_load_uniform_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec3<u32>
+fn ub_load_10(offset : u32) -> vec3<u32>
 
 @internal(intrinsic_load_uniform_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec3<f16>
+fn ub_load_11(offset : u32) -> vec3<f16>
 
 @internal(intrinsic_load_uniform_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec4<f32>
+fn ub_load_12(offset : u32) -> vec4<f32>
 
 @internal(intrinsic_load_uniform_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec4<i32>
+fn ub_load_13(offset : u32) -> vec4<i32>
 
 @internal(intrinsic_load_uniform_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec4<u32>
+fn ub_load_14(offset : u32) -> vec4<u32>
 
 @internal(intrinsic_load_uniform_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> vec4<f16>
+fn ub_load_15(offset : u32) -> vec4<f16>
 
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x2<f32> {
-  return mat2x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)));
+fn ub_load_16(offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)));
 }
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x3<f32> {
-  return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
+fn ub_load_17(offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)));
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x4<f32> {
-  return mat2x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)));
+fn ub_load_18(offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)));
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x2<f32> {
-  return mat3x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)));
+fn ub_load_19(offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)), ub_load_4((offset + 16u)));
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, 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 ub_load_20(offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)), ub_load_8((offset + 32u)));
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x4<f32> {
-  return mat3x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)));
+fn ub_load_21(offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)), ub_load_12((offset + 32u)));
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x2<f32> {
-  return mat4x2<f32>(tint_symbol_4(buffer, (offset + 0u)), tint_symbol_4(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)), tint_symbol_4(buffer, (offset + 24u)));
+fn ub_load_22(offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)), ub_load_4((offset + 16u)), ub_load_4((offset + 24u)));
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, 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 ub_load_23(offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)), ub_load_8((offset + 32u)), ub_load_8((offset + 48u)));
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x4<f32> {
-  return mat4x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)), tint_symbol_12(buffer, (offset + 48u)));
+fn ub_load_24(offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)), ub_load_12((offset + 32u)), ub_load_12((offset + 48u)));
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x2<f16> {
-  return mat2x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)));
+fn ub_load_25(offset : u32) -> mat2x2<f16> {
+  return mat2x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)));
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x3<f16> {
-  return mat2x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)));
+fn ub_load_26(offset : u32) -> mat2x3<f16> {
+  return mat2x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)));
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat2x4<f16> {
-  return mat2x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)));
+fn ub_load_27(offset : u32) -> mat2x4<f16> {
+  return mat2x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)));
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x2<f16> {
-  return mat3x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)), tint_symbol_7(buffer, (offset + 8u)));
+fn ub_load_28(offset : u32) -> mat3x2<f16> {
+  return mat3x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)), ub_load_7((offset + 8u)));
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x3<f16> {
-  return mat3x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)), tint_symbol_11(buffer, (offset + 16u)));
+fn ub_load_29(offset : u32) -> mat3x3<f16> {
+  return mat3x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)), ub_load_11((offset + 16u)));
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat3x4<f16> {
-  return mat3x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)), tint_symbol_15(buffer, (offset + 16u)));
+fn ub_load_30(offset : u32) -> mat3x4<f16> {
+  return mat3x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)), ub_load_15((offset + 16u)));
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x2<f16> {
-  return mat4x2<f16>(tint_symbol_7(buffer, (offset + 0u)), tint_symbol_7(buffer, (offset + 4u)), tint_symbol_7(buffer, (offset + 8u)), tint_symbol_7(buffer, (offset + 12u)));
+fn ub_load_31(offset : u32) -> mat4x2<f16> {
+  return mat4x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)), ub_load_7((offset + 8u)), ub_load_7((offset + 12u)));
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x3<f16> {
-  return mat4x3<f16>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 8u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 24u)));
+fn ub_load_32(offset : u32) -> mat4x3<f16> {
+  return mat4x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)), ub_load_11((offset + 16u)), ub_load_11((offset + 24u)));
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> mat4x4<f16> {
-  return mat4x4<f16>(tint_symbol_15(buffer, (offset + 0u)), tint_symbol_15(buffer, (offset + 8u)), tint_symbol_15(buffer, (offset + 16u)), tint_symbol_15(buffer, (offset + 24u)));
+fn ub_load_33(offset : u32) -> mat4x4<f16> {
+  return mat4x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)), ub_load_15((offset + 16u)), ub_load_15((offset + 24u)));
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> array<vec3<f32>, 2u> {
+fn ub_load_34(offset : u32) -> array<vec3<f32>, 2u> {
   var arr : array<vec3<f32>, 2u>;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    arr[i] = tint_symbol_8(buffer, (offset + (i * 16u)));
+    arr[i] = ub_load_8((offset + (i * 16u)));
   }
   return arr;
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<uniform, UB>, offset : u32) -> array<mat4x2<f16>, 2u> {
+fn ub_load_35(offset : u32) -> array<mat4x2<f16>, 2u> {
   var arr_1 : array<mat4x2<f16>, 2u>;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    arr_1[i_1] = tint_symbol_31(buffer, (offset + (i_1 * 16u)));
+    arr_1[i_1] = ub_load_31((offset + (i_1 * 16u)));
   }
   return arr_1;
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  var scalar_f32 : f32 = tint_symbol(&(ub), 0u);
-  var scalar_i32 : i32 = tint_symbol_1(&(ub), 4u);
-  var scalar_u32 : u32 = tint_symbol_2(&(ub), 8u);
-  var scalar_f16 : f16 = tint_symbol_3(&(ub), 12u);
-  var vec2_f32 : vec2<f32> = tint_symbol_4(&(ub), 16u);
-  var vec2_i32 : vec2<i32> = tint_symbol_5(&(ub), 24u);
-  var vec2_u32 : vec2<u32> = tint_symbol_6(&(ub), 32u);
-  var vec2_f16 : vec2<f16> = tint_symbol_7(&(ub), 40u);
-  var vec3_f32 : vec3<f32> = tint_symbol_8(&(ub), 48u);
-  var vec3_i32 : vec3<i32> = tint_symbol_9(&(ub), 64u);
-  var vec3_u32 : vec3<u32> = tint_symbol_10(&(ub), 80u);
-  var vec3_f16 : vec3<f16> = tint_symbol_11(&(ub), 96u);
-  var vec4_f32 : vec4<f32> = tint_symbol_12(&(ub), 112u);
-  var vec4_i32 : vec4<i32> = tint_symbol_13(&(ub), 128u);
-  var vec4_u32 : vec4<u32> = tint_symbol_14(&(ub), 144u);
-  var vec4_f16 : vec4<f16> = tint_symbol_15(&(ub), 160u);
-  var mat2x2_f32 : mat2x2<f32> = tint_symbol_16(&(ub), 168u);
-  var mat2x3_f32 : mat2x3<f32> = tint_symbol_17(&(ub), 192u);
-  var mat2x4_f32 : mat2x4<f32> = tint_symbol_18(&(ub), 224u);
-  var mat3x2_f32 : mat3x2<f32> = tint_symbol_19(&(ub), 256u);
-  var mat3x3_f32 : mat3x3<f32> = tint_symbol_20(&(ub), 288u);
-  var mat3x4_f32 : mat3x4<f32> = tint_symbol_21(&(ub), 336u);
-  var mat4x2_f32 : mat4x2<f32> = tint_symbol_22(&(ub), 384u);
-  var mat4x3_f32 : mat4x3<f32> = tint_symbol_23(&(ub), 416u);
-  var mat4x4_f32 : mat4x4<f32> = tint_symbol_24(&(ub), 480u);
-  var mat2x2_f16 : mat2x2<f16> = tint_symbol_25(&(ub), 544u);
-  var mat2x3_f16 : mat2x3<f16> = tint_symbol_26(&(ub), 552u);
-  var mat2x4_f16 : mat2x4<f16> = tint_symbol_27(&(ub), 568u);
-  var mat3x2_f16 : mat3x2<f16> = tint_symbol_28(&(ub), 584u);
-  var mat3x3_f16 : mat3x3<f16> = tint_symbol_29(&(ub), 600u);
-  var mat3x4_f16 : mat3x4<f16> = tint_symbol_30(&(ub), 624u);
-  var mat4x2_f16 : mat4x2<f16> = tint_symbol_31(&(ub), 648u);
-  var mat4x3_f16 : mat4x3<f16> = tint_symbol_32(&(ub), 664u);
-  var mat4x4_f16 : mat4x4<f16> = tint_symbol_33(&(ub), 696u);
-  var arr2_vec3_f32 : array<vec3<f32>, 2> = tint_symbol_34(&(ub), 736u);
-  var arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = tint_symbol_35(&(ub), 768u);
+  var scalar_f32 : f32 = ub_load(0u);
+  var scalar_i32 : i32 = ub_load_1(4u);
+  var scalar_u32 : u32 = ub_load_2(8u);
+  var scalar_f16 : f16 = ub_load_3(12u);
+  var vec2_f32 : vec2<f32> = ub_load_4(16u);
+  var vec2_i32 : vec2<i32> = ub_load_5(24u);
+  var vec2_u32 : vec2<u32> = ub_load_6(32u);
+  var vec2_f16 : vec2<f16> = ub_load_7(40u);
+  var vec3_f32 : vec3<f32> = ub_load_8(48u);
+  var vec3_i32 : vec3<i32> = ub_load_9(64u);
+  var vec3_u32 : vec3<u32> = ub_load_10(80u);
+  var vec3_f16 : vec3<f16> = ub_load_11(96u);
+  var vec4_f32 : vec4<f32> = ub_load_12(112u);
+  var vec4_i32 : vec4<i32> = ub_load_13(128u);
+  var vec4_u32 : vec4<u32> = ub_load_14(144u);
+  var vec4_f16 : vec4<f16> = ub_load_15(160u);
+  var mat2x2_f32 : mat2x2<f32> = ub_load_16(168u);
+  var mat2x3_f32 : mat2x3<f32> = ub_load_17(192u);
+  var mat2x4_f32 : mat2x4<f32> = ub_load_18(224u);
+  var mat3x2_f32 : mat3x2<f32> = ub_load_19(256u);
+  var mat3x3_f32 : mat3x3<f32> = ub_load_20(288u);
+  var mat3x4_f32 : mat3x4<f32> = ub_load_21(336u);
+  var mat4x2_f32 : mat4x2<f32> = ub_load_22(384u);
+  var mat4x3_f32 : mat4x3<f32> = ub_load_23(416u);
+  var mat4x4_f32 : mat4x4<f32> = ub_load_24(480u);
+  var mat2x2_f16 : mat2x2<f16> = ub_load_25(544u);
+  var mat2x3_f16 : mat2x3<f16> = ub_load_26(552u);
+  var mat2x4_f16 : mat2x4<f16> = ub_load_27(568u);
+  var mat3x2_f16 : mat3x2<f16> = ub_load_28(584u);
+  var mat3x3_f16 : mat3x3<f16> = ub_load_29(600u);
+  var mat3x4_f16 : mat3x4<f16> = ub_load_30(624u);
+  var mat4x2_f16 : mat4x2<f16> = ub_load_31(648u);
+  var mat4x3_f16 : mat4x3<f16> = ub_load_32(664u);
+  var mat4x4_f16 : mat4x4<f16> = ub_load_33(696u);
+  var arr2_vec3_f32 : array<vec3<f32>, 2> = ub_load_34(736u);
+  var arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = ub_load_35(768u);
 }
 
 @group(0) @binding(0) var<uniform> ub : UB;
@@ -1428,213 +1428,213 @@
 @group(0) @binding(0) var<storage, read_write> sb : SB;
 
 @internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f32)
+fn sb_store(offset : u32, value : f32)
 
 @internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : i32)
+fn sb_store_1(offset : u32, value : i32)
 
 @internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : u32)
+fn sb_store_2(offset : u32, value : u32)
 
 @internal(intrinsic_store_storage_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f16)
+fn sb_store_3(offset : u32, value : f16)
 
 @internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f32>)
+fn sb_store_4(offset : u32, value : vec2<f32>)
 
 @internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<i32>)
+fn sb_store_5(offset : u32, value : vec2<i32>)
 
 @internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<u32>)
+fn sb_store_6(offset : u32, value : vec2<u32>)
 
 @internal(intrinsic_store_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f16>)
+fn sb_store_7(offset : u32, value : vec2<f16>)
 
 @internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f32>)
+fn sb_store_8(offset : u32, value : vec3<f32>)
 
 @internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<i32>)
+fn sb_store_9(offset : u32, value : vec3<i32>)
 
 @internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<u32>)
+fn sb_store_10(offset : u32, value : vec3<u32>)
 
 @internal(intrinsic_store_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f16>)
+fn sb_store_11(offset : u32, value : vec3<f16>)
 
 @internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f32>)
+fn sb_store_12(offset : u32, value : vec4<f32>)
 
 @internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<i32>)
+fn sb_store_13(offset : u32, value : vec4<i32>)
 
 @internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<u32>)
+fn sb_store_14(offset : u32, value : vec4<u32>)
 
 @internal(intrinsic_store_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f16>)
+fn sb_store_15(offset : u32, value : vec4<f16>)
 
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f32>) {
-  tint_symbol_4(buffer, (offset + 0u), value[0u]);
-  tint_symbol_4(buffer, (offset + 8u), value[1u]);
+fn sb_store_16(offset : u32, value : mat2x2<f32>) {
+  sb_store_4((offset + 0u), value[0u]);
+  sb_store_4((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f32>) {
-  tint_symbol_8(buffer, (offset + 0u), value[0u]);
-  tint_symbol_8(buffer, (offset + 16u), value[1u]);
+fn sb_store_17(offset : u32, value : mat2x3<f32>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 16u), value[1u]);
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f32>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 16u), value[1u]);
+fn sb_store_18(offset : u32, value : mat2x4<f32>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 16u), value[1u]);
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f32>) {
-  tint_symbol_4(buffer, (offset + 0u), value[0u]);
-  tint_symbol_4(buffer, (offset + 8u), value[1u]);
-  tint_symbol_4(buffer, (offset + 16u), value[2u]);
+fn sb_store_19(offset : u32, value : mat3x2<f32>) {
+  sb_store_4((offset + 0u), value[0u]);
+  sb_store_4((offset + 8u), value[1u]);
+  sb_store_4((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_store_20(offset : u32, value : mat3x3<f32>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 16u), value[1u]);
+  sb_store_8((offset + 32u), value[2u]);
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f32>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 16u), value[1u]);
-  tint_symbol_12(buffer, (offset + 32u), value[2u]);
+fn sb_store_21(offset : u32, value : mat3x4<f32>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 16u), value[1u]);
+  sb_store_12((offset + 32u), value[2u]);
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f32>) {
-  tint_symbol_4(buffer, (offset + 0u), value[0u]);
-  tint_symbol_4(buffer, (offset + 8u), value[1u]);
-  tint_symbol_4(buffer, (offset + 16u), value[2u]);
-  tint_symbol_4(buffer, (offset + 24u), value[3u]);
+fn sb_store_22(offset : u32, value : mat4x2<f32>) {
+  sb_store_4((offset + 0u), value[0u]);
+  sb_store_4((offset + 8u), value[1u]);
+  sb_store_4((offset + 16u), value[2u]);
+  sb_store_4((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_store_23(offset : u32, value : mat4x3<f32>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 16u), value[1u]);
+  sb_store_8((offset + 32u), value[2u]);
+  sb_store_8((offset + 48u), value[3u]);
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f32>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 16u), value[1u]);
-  tint_symbol_12(buffer, (offset + 32u), value[2u]);
-  tint_symbol_12(buffer, (offset + 48u), value[3u]);
+fn sb_store_24(offset : u32, value : mat4x4<f32>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 16u), value[1u]);
+  sb_store_12((offset + 32u), value[2u]);
+  sb_store_12((offset + 48u), value[3u]);
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f16>) {
-  tint_symbol_7(buffer, (offset + 0u), value[0u]);
-  tint_symbol_7(buffer, (offset + 4u), value[1u]);
+fn sb_store_25(offset : u32, value : mat2x2<f16>) {
+  sb_store_7((offset + 0u), value[0u]);
+  sb_store_7((offset + 4u), value[1u]);
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f16>) {
-  tint_symbol_11(buffer, (offset + 0u), value[0u]);
-  tint_symbol_11(buffer, (offset + 8u), value[1u]);
+fn sb_store_26(offset : u32, value : mat2x3<f16>) {
+  sb_store_11((offset + 0u), value[0u]);
+  sb_store_11((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f16>) {
-  tint_symbol_15(buffer, (offset + 0u), value[0u]);
-  tint_symbol_15(buffer, (offset + 8u), value[1u]);
+fn sb_store_27(offset : u32, value : mat2x4<f16>) {
+  sb_store_15((offset + 0u), value[0u]);
+  sb_store_15((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f16>) {
-  tint_symbol_7(buffer, (offset + 0u), value[0u]);
-  tint_symbol_7(buffer, (offset + 4u), value[1u]);
-  tint_symbol_7(buffer, (offset + 8u), value[2u]);
+fn sb_store_28(offset : u32, value : mat3x2<f16>) {
+  sb_store_7((offset + 0u), value[0u]);
+  sb_store_7((offset + 4u), value[1u]);
+  sb_store_7((offset + 8u), value[2u]);
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f16>) {
-  tint_symbol_11(buffer, (offset + 0u), value[0u]);
-  tint_symbol_11(buffer, (offset + 8u), value[1u]);
-  tint_symbol_11(buffer, (offset + 16u), value[2u]);
+fn sb_store_29(offset : u32, value : mat3x3<f16>) {
+  sb_store_11((offset + 0u), value[0u]);
+  sb_store_11((offset + 8u), value[1u]);
+  sb_store_11((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f16>) {
-  tint_symbol_15(buffer, (offset + 0u), value[0u]);
-  tint_symbol_15(buffer, (offset + 8u), value[1u]);
-  tint_symbol_15(buffer, (offset + 16u), value[2u]);
+fn sb_store_30(offset : u32, value : mat3x4<f16>) {
+  sb_store_15((offset + 0u), value[0u]);
+  sb_store_15((offset + 8u), value[1u]);
+  sb_store_15((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f16>) {
-  tint_symbol_7(buffer, (offset + 0u), value[0u]);
-  tint_symbol_7(buffer, (offset + 4u), value[1u]);
-  tint_symbol_7(buffer, (offset + 8u), value[2u]);
-  tint_symbol_7(buffer, (offset + 12u), value[3u]);
+fn sb_store_31(offset : u32, value : mat4x2<f16>) {
+  sb_store_7((offset + 0u), value[0u]);
+  sb_store_7((offset + 4u), value[1u]);
+  sb_store_7((offset + 8u), value[2u]);
+  sb_store_7((offset + 12u), value[3u]);
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f16>) {
-  tint_symbol_11(buffer, (offset + 0u), value[0u]);
-  tint_symbol_11(buffer, (offset + 8u), value[1u]);
-  tint_symbol_11(buffer, (offset + 16u), value[2u]);
-  tint_symbol_11(buffer, (offset + 24u), value[3u]);
+fn sb_store_32(offset : u32, value : mat4x3<f16>) {
+  sb_store_11((offset + 0u), value[0u]);
+  sb_store_11((offset + 8u), value[1u]);
+  sb_store_11((offset + 16u), value[2u]);
+  sb_store_11((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f16>) {
-  tint_symbol_15(buffer, (offset + 0u), value[0u]);
-  tint_symbol_15(buffer, (offset + 8u), value[1u]);
-  tint_symbol_15(buffer, (offset + 16u), value[2u]);
-  tint_symbol_15(buffer, (offset + 24u), value[3u]);
+fn sb_store_33(offset : u32, value : mat4x4<f16>) {
+  sb_store_15((offset + 0u), value[0u]);
+  sb_store_15((offset + 8u), value[1u]);
+  sb_store_15((offset + 16u), value[2u]);
+  sb_store_15((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<vec3<f32>, 2u>) {
+fn sb_store_34(offset : u32, value : array<vec3<f32>, 2u>) {
   var array_1 = value;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    tint_symbol_8(buffer, (offset + (i * 16u)), array_1[i]);
+    sb_store_8((offset + (i * 16u)), array_1[i]);
   }
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<mat4x2<f16>, 2u>) {
+fn sb_store_35(offset : u32, value : array<mat4x2<f16>, 2u>) {
   var array_2 = value;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    tint_symbol_31(buffer, (offset + (i_1 * 16u)), array_2[i_1]);
+    sb_store_31((offset + (i_1 * 16u)), array_2[i_1]);
   }
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  tint_symbol(&(sb), 0u, f32());
-  tint_symbol_1(&(sb), 4u, i32());
-  tint_symbol_2(&(sb), 8u, u32());
-  tint_symbol_3(&(sb), 12u, f16());
-  tint_symbol_4(&(sb), 16u, vec2<f32>());
-  tint_symbol_5(&(sb), 24u, vec2<i32>());
-  tint_symbol_6(&(sb), 32u, vec2<u32>());
-  tint_symbol_7(&(sb), 40u, vec2<f16>());
-  tint_symbol_8(&(sb), 48u, vec3<f32>());
-  tint_symbol_9(&(sb), 64u, vec3<i32>());
-  tint_symbol_10(&(sb), 80u, vec3<u32>());
-  tint_symbol_11(&(sb), 96u, vec3<f16>());
-  tint_symbol_12(&(sb), 112u, vec4<f32>());
-  tint_symbol_13(&(sb), 128u, vec4<i32>());
-  tint_symbol_14(&(sb), 144u, vec4<u32>());
-  tint_symbol_15(&(sb), 160u, vec4<f16>());
-  tint_symbol_16(&(sb), 168u, mat2x2<f32>());
-  tint_symbol_17(&(sb), 192u, mat2x3<f32>());
-  tint_symbol_18(&(sb), 224u, mat2x4<f32>());
-  tint_symbol_19(&(sb), 256u, mat3x2<f32>());
-  tint_symbol_20(&(sb), 288u, mat3x3<f32>());
-  tint_symbol_21(&(sb), 336u, mat3x4<f32>());
-  tint_symbol_22(&(sb), 384u, mat4x2<f32>());
-  tint_symbol_23(&(sb), 416u, mat4x3<f32>());
-  tint_symbol_24(&(sb), 480u, mat4x4<f32>());
-  tint_symbol_25(&(sb), 544u, mat2x2<f16>());
-  tint_symbol_26(&(sb), 552u, mat2x3<f16>());
-  tint_symbol_27(&(sb), 568u, mat2x4<f16>());
-  tint_symbol_28(&(sb), 584u, mat3x2<f16>());
-  tint_symbol_29(&(sb), 600u, mat3x3<f16>());
-  tint_symbol_30(&(sb), 624u, mat3x4<f16>());
-  tint_symbol_31(&(sb), 648u, mat4x2<f16>());
-  tint_symbol_32(&(sb), 664u, mat4x3<f16>());
-  tint_symbol_33(&(sb), 696u, mat4x4<f16>());
-  tint_symbol_34(&(sb), 736u, array<vec3<f32>, 2>());
-  tint_symbol_35(&(sb), 768u, array<mat4x2<f16>, 2>());
+  sb_store(0u, f32());
+  sb_store_1(4u, i32());
+  sb_store_2(8u, u32());
+  sb_store_3(12u, f16());
+  sb_store_4(16u, vec2<f32>());
+  sb_store_5(24u, vec2<i32>());
+  sb_store_6(32u, vec2<u32>());
+  sb_store_7(40u, vec2<f16>());
+  sb_store_8(48u, vec3<f32>());
+  sb_store_9(64u, vec3<i32>());
+  sb_store_10(80u, vec3<u32>());
+  sb_store_11(96u, vec3<f16>());
+  sb_store_12(112u, vec4<f32>());
+  sb_store_13(128u, vec4<i32>());
+  sb_store_14(144u, vec4<u32>());
+  sb_store_15(160u, vec4<f16>());
+  sb_store_16(168u, mat2x2<f32>());
+  sb_store_17(192u, mat2x3<f32>());
+  sb_store_18(224u, mat2x4<f32>());
+  sb_store_19(256u, mat3x2<f32>());
+  sb_store_20(288u, mat3x3<f32>());
+  sb_store_21(336u, mat3x4<f32>());
+  sb_store_22(384u, mat4x2<f32>());
+  sb_store_23(416u, mat4x3<f32>());
+  sb_store_24(480u, mat4x4<f32>());
+  sb_store_25(544u, mat2x2<f16>());
+  sb_store_26(552u, mat2x3<f16>());
+  sb_store_27(568u, mat2x4<f16>());
+  sb_store_28(584u, mat3x2<f16>());
+  sb_store_29(600u, mat3x3<f16>());
+  sb_store_30(624u, mat3x4<f16>());
+  sb_store_31(648u, mat4x2<f16>());
+  sb_store_32(664u, mat4x3<f16>());
+  sb_store_33(696u, mat4x4<f16>());
+  sb_store_34(736u, array<vec3<f32>, 2>());
+  sb_store_35(768u, array<mat4x2<f16>, 2>());
 }
 )";
 
@@ -1733,213 +1733,213 @@
 enable f16;
 
 @internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f32)
+fn sb_store(offset : u32, value : f32)
 
 @internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : i32)
+fn sb_store_1(offset : u32, value : i32)
 
 @internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : u32)
+fn sb_store_2(offset : u32, value : u32)
 
 @internal(intrinsic_store_storage_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f16)
+fn sb_store_3(offset : u32, value : f16)
 
 @internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f32>)
+fn sb_store_4(offset : u32, value : vec2<f32>)
 
 @internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<i32>)
+fn sb_store_5(offset : u32, value : vec2<i32>)
 
 @internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<u32>)
+fn sb_store_6(offset : u32, value : vec2<u32>)
 
 @internal(intrinsic_store_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f16>)
+fn sb_store_7(offset : u32, value : vec2<f16>)
 
 @internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f32>)
+fn sb_store_8(offset : u32, value : vec3<f32>)
 
 @internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<i32>)
+fn sb_store_9(offset : u32, value : vec3<i32>)
 
 @internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<u32>)
+fn sb_store_10(offset : u32, value : vec3<u32>)
 
 @internal(intrinsic_store_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f16>)
+fn sb_store_11(offset : u32, value : vec3<f16>)
 
 @internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f32>)
+fn sb_store_12(offset : u32, value : vec4<f32>)
 
 @internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<i32>)
+fn sb_store_13(offset : u32, value : vec4<i32>)
 
 @internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<u32>)
+fn sb_store_14(offset : u32, value : vec4<u32>)
 
 @internal(intrinsic_store_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f16>)
+fn sb_store_15(offset : u32, value : vec4<f16>)
 
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f32>) {
-  tint_symbol_4(buffer, (offset + 0u), value[0u]);
-  tint_symbol_4(buffer, (offset + 8u), value[1u]);
+fn sb_store_16(offset : u32, value : mat2x2<f32>) {
+  sb_store_4((offset + 0u), value[0u]);
+  sb_store_4((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f32>) {
-  tint_symbol_8(buffer, (offset + 0u), value[0u]);
-  tint_symbol_8(buffer, (offset + 16u), value[1u]);
+fn sb_store_17(offset : u32, value : mat2x3<f32>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 16u), value[1u]);
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f32>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 16u), value[1u]);
+fn sb_store_18(offset : u32, value : mat2x4<f32>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 16u), value[1u]);
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f32>) {
-  tint_symbol_4(buffer, (offset + 0u), value[0u]);
-  tint_symbol_4(buffer, (offset + 8u), value[1u]);
-  tint_symbol_4(buffer, (offset + 16u), value[2u]);
+fn sb_store_19(offset : u32, value : mat3x2<f32>) {
+  sb_store_4((offset + 0u), value[0u]);
+  sb_store_4((offset + 8u), value[1u]);
+  sb_store_4((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_store_20(offset : u32, value : mat3x3<f32>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 16u), value[1u]);
+  sb_store_8((offset + 32u), value[2u]);
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f32>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 16u), value[1u]);
-  tint_symbol_12(buffer, (offset + 32u), value[2u]);
+fn sb_store_21(offset : u32, value : mat3x4<f32>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 16u), value[1u]);
+  sb_store_12((offset + 32u), value[2u]);
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f32>) {
-  tint_symbol_4(buffer, (offset + 0u), value[0u]);
-  tint_symbol_4(buffer, (offset + 8u), value[1u]);
-  tint_symbol_4(buffer, (offset + 16u), value[2u]);
-  tint_symbol_4(buffer, (offset + 24u), value[3u]);
+fn sb_store_22(offset : u32, value : mat4x2<f32>) {
+  sb_store_4((offset + 0u), value[0u]);
+  sb_store_4((offset + 8u), value[1u]);
+  sb_store_4((offset + 16u), value[2u]);
+  sb_store_4((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_store_23(offset : u32, value : mat4x3<f32>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 16u), value[1u]);
+  sb_store_8((offset + 32u), value[2u]);
+  sb_store_8((offset + 48u), value[3u]);
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f32>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 16u), value[1u]);
-  tint_symbol_12(buffer, (offset + 32u), value[2u]);
-  tint_symbol_12(buffer, (offset + 48u), value[3u]);
+fn sb_store_24(offset : u32, value : mat4x4<f32>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 16u), value[1u]);
+  sb_store_12((offset + 32u), value[2u]);
+  sb_store_12((offset + 48u), value[3u]);
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f16>) {
-  tint_symbol_7(buffer, (offset + 0u), value[0u]);
-  tint_symbol_7(buffer, (offset + 4u), value[1u]);
+fn sb_store_25(offset : u32, value : mat2x2<f16>) {
+  sb_store_7((offset + 0u), value[0u]);
+  sb_store_7((offset + 4u), value[1u]);
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f16>) {
-  tint_symbol_11(buffer, (offset + 0u), value[0u]);
-  tint_symbol_11(buffer, (offset + 8u), value[1u]);
+fn sb_store_26(offset : u32, value : mat2x3<f16>) {
+  sb_store_11((offset + 0u), value[0u]);
+  sb_store_11((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f16>) {
-  tint_symbol_15(buffer, (offset + 0u), value[0u]);
-  tint_symbol_15(buffer, (offset + 8u), value[1u]);
+fn sb_store_27(offset : u32, value : mat2x4<f16>) {
+  sb_store_15((offset + 0u), value[0u]);
+  sb_store_15((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f16>) {
-  tint_symbol_7(buffer, (offset + 0u), value[0u]);
-  tint_symbol_7(buffer, (offset + 4u), value[1u]);
-  tint_symbol_7(buffer, (offset + 8u), value[2u]);
+fn sb_store_28(offset : u32, value : mat3x2<f16>) {
+  sb_store_7((offset + 0u), value[0u]);
+  sb_store_7((offset + 4u), value[1u]);
+  sb_store_7((offset + 8u), value[2u]);
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f16>) {
-  tint_symbol_11(buffer, (offset + 0u), value[0u]);
-  tint_symbol_11(buffer, (offset + 8u), value[1u]);
-  tint_symbol_11(buffer, (offset + 16u), value[2u]);
+fn sb_store_29(offset : u32, value : mat3x3<f16>) {
+  sb_store_11((offset + 0u), value[0u]);
+  sb_store_11((offset + 8u), value[1u]);
+  sb_store_11((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f16>) {
-  tint_symbol_15(buffer, (offset + 0u), value[0u]);
-  tint_symbol_15(buffer, (offset + 8u), value[1u]);
-  tint_symbol_15(buffer, (offset + 16u), value[2u]);
+fn sb_store_30(offset : u32, value : mat3x4<f16>) {
+  sb_store_15((offset + 0u), value[0u]);
+  sb_store_15((offset + 8u), value[1u]);
+  sb_store_15((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f16>) {
-  tint_symbol_7(buffer, (offset + 0u), value[0u]);
-  tint_symbol_7(buffer, (offset + 4u), value[1u]);
-  tint_symbol_7(buffer, (offset + 8u), value[2u]);
-  tint_symbol_7(buffer, (offset + 12u), value[3u]);
+fn sb_store_31(offset : u32, value : mat4x2<f16>) {
+  sb_store_7((offset + 0u), value[0u]);
+  sb_store_7((offset + 4u), value[1u]);
+  sb_store_7((offset + 8u), value[2u]);
+  sb_store_7((offset + 12u), value[3u]);
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f16>) {
-  tint_symbol_11(buffer, (offset + 0u), value[0u]);
-  tint_symbol_11(buffer, (offset + 8u), value[1u]);
-  tint_symbol_11(buffer, (offset + 16u), value[2u]);
-  tint_symbol_11(buffer, (offset + 24u), value[3u]);
+fn sb_store_32(offset : u32, value : mat4x3<f16>) {
+  sb_store_11((offset + 0u), value[0u]);
+  sb_store_11((offset + 8u), value[1u]);
+  sb_store_11((offset + 16u), value[2u]);
+  sb_store_11((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f16>) {
-  tint_symbol_15(buffer, (offset + 0u), value[0u]);
-  tint_symbol_15(buffer, (offset + 8u), value[1u]);
-  tint_symbol_15(buffer, (offset + 16u), value[2u]);
-  tint_symbol_15(buffer, (offset + 24u), value[3u]);
+fn sb_store_33(offset : u32, value : mat4x4<f16>) {
+  sb_store_15((offset + 0u), value[0u]);
+  sb_store_15((offset + 8u), value[1u]);
+  sb_store_15((offset + 16u), value[2u]);
+  sb_store_15((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<vec3<f32>, 2u>) {
+fn sb_store_34(offset : u32, value : array<vec3<f32>, 2u>) {
   var array_1 = value;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    tint_symbol_8(buffer, (offset + (i * 16u)), array_1[i]);
+    sb_store_8((offset + (i * 16u)), array_1[i]);
   }
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<mat4x2<f16>, 2u>) {
+fn sb_store_35(offset : u32, value : array<mat4x2<f16>, 2u>) {
   var array_2 = value;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    tint_symbol_31(buffer, (offset + (i_1 * 16u)), array_2[i_1]);
+    sb_store_31((offset + (i_1 * 16u)), array_2[i_1]);
   }
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  tint_symbol(&(sb), 0u, f32());
-  tint_symbol_1(&(sb), 4u, i32());
-  tint_symbol_2(&(sb), 8u, u32());
-  tint_symbol_3(&(sb), 12u, f16());
-  tint_symbol_4(&(sb), 16u, vec2<f32>());
-  tint_symbol_5(&(sb), 24u, vec2<i32>());
-  tint_symbol_6(&(sb), 32u, vec2<u32>());
-  tint_symbol_7(&(sb), 40u, vec2<f16>());
-  tint_symbol_8(&(sb), 48u, vec3<f32>());
-  tint_symbol_9(&(sb), 64u, vec3<i32>());
-  tint_symbol_10(&(sb), 80u, vec3<u32>());
-  tint_symbol_11(&(sb), 96u, vec3<f16>());
-  tint_symbol_12(&(sb), 112u, vec4<f32>());
-  tint_symbol_13(&(sb), 128u, vec4<i32>());
-  tint_symbol_14(&(sb), 144u, vec4<u32>());
-  tint_symbol_15(&(sb), 160u, vec4<f16>());
-  tint_symbol_16(&(sb), 168u, mat2x2<f32>());
-  tint_symbol_17(&(sb), 192u, mat2x3<f32>());
-  tint_symbol_18(&(sb), 224u, mat2x4<f32>());
-  tint_symbol_19(&(sb), 256u, mat3x2<f32>());
-  tint_symbol_20(&(sb), 288u, mat3x3<f32>());
-  tint_symbol_21(&(sb), 336u, mat3x4<f32>());
-  tint_symbol_22(&(sb), 384u, mat4x2<f32>());
-  tint_symbol_23(&(sb), 416u, mat4x3<f32>());
-  tint_symbol_24(&(sb), 480u, mat4x4<f32>());
-  tint_symbol_25(&(sb), 544u, mat2x2<f16>());
-  tint_symbol_26(&(sb), 552u, mat2x3<f16>());
-  tint_symbol_27(&(sb), 568u, mat2x4<f16>());
-  tint_symbol_28(&(sb), 584u, mat3x2<f16>());
-  tint_symbol_29(&(sb), 600u, mat3x3<f16>());
-  tint_symbol_30(&(sb), 624u, mat3x4<f16>());
-  tint_symbol_31(&(sb), 648u, mat4x2<f16>());
-  tint_symbol_32(&(sb), 664u, mat4x3<f16>());
-  tint_symbol_33(&(sb), 696u, mat4x4<f16>());
-  tint_symbol_34(&(sb), 736u, array<vec3<f32>, 2>());
-  tint_symbol_35(&(sb), 768u, array<mat4x2<f16>, 2>());
+  sb_store(0u, f32());
+  sb_store_1(4u, i32());
+  sb_store_2(8u, u32());
+  sb_store_3(12u, f16());
+  sb_store_4(16u, vec2<f32>());
+  sb_store_5(24u, vec2<i32>());
+  sb_store_6(32u, vec2<u32>());
+  sb_store_7(40u, vec2<f16>());
+  sb_store_8(48u, vec3<f32>());
+  sb_store_9(64u, vec3<i32>());
+  sb_store_10(80u, vec3<u32>());
+  sb_store_11(96u, vec3<f16>());
+  sb_store_12(112u, vec4<f32>());
+  sb_store_13(128u, vec4<i32>());
+  sb_store_14(144u, vec4<u32>());
+  sb_store_15(160u, vec4<f16>());
+  sb_store_16(168u, mat2x2<f32>());
+  sb_store_17(192u, mat2x3<f32>());
+  sb_store_18(224u, mat2x4<f32>());
+  sb_store_19(256u, mat3x2<f32>());
+  sb_store_20(288u, mat3x3<f32>());
+  sb_store_21(336u, mat3x4<f32>());
+  sb_store_22(384u, mat4x2<f32>());
+  sb_store_23(416u, mat4x3<f32>());
+  sb_store_24(480u, mat4x4<f32>());
+  sb_store_25(544u, mat2x2<f16>());
+  sb_store_26(552u, mat2x3<f16>());
+  sb_store_27(568u, mat2x4<f16>());
+  sb_store_28(584u, mat3x2<f16>());
+  sb_store_29(600u, mat3x3<f16>());
+  sb_store_30(624u, mat3x4<f16>());
+  sb_store_31(648u, mat4x2<f16>());
+  sb_store_32(664u, mat4x3<f16>());
+  sb_store_33(696u, mat4x4<f16>());
+  sb_store_34(736u, array<vec3<f32>, 2>());
+  sb_store_35(768u, array<mat4x2<f16>, 2>());
 }
 
 @group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -2085,148 +2085,148 @@
 @group(0) @binding(0) var<storage, read_write> sb : SB;
 
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load_1(offset : u32) -> f32
 
 @internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
+fn sb_load_2(offset : u32) -> i32
 
 @internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
+fn sb_load_3(offset : u32) -> u32
 
 @internal(intrinsic_load_storage_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f16
+fn sb_load_4(offset : u32) -> f16
 
 @internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f32>
+fn sb_load_5(offset : u32) -> vec2<f32>
 
 @internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<i32>
+fn sb_load_6(offset : u32) -> vec2<i32>
 
 @internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<u32>
+fn sb_load_7(offset : u32) -> vec2<u32>
 
 @internal(intrinsic_load_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f16>
+fn sb_load_8(offset : u32) -> vec2<f16>
 
 @internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f32>
+fn sb_load_9(offset : u32) -> vec3<f32>
 
 @internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<i32>
+fn sb_load_10(offset : u32) -> vec3<i32>
 
 @internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<u32>
+fn sb_load_11(offset : u32) -> vec3<u32>
 
 @internal(intrinsic_load_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f16>
+fn sb_load_12(offset : u32) -> vec3<f16>
 
 @internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f32>
+fn sb_load_13(offset : u32) -> vec4<f32>
 
 @internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<i32>
+fn sb_load_14(offset : u32) -> vec4<i32>
 
 @internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<u32>
+fn sb_load_15(offset : u32) -> vec4<u32>
 
 @internal(intrinsic_load_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f16>
+fn sb_load_16(offset : u32) -> vec4<f16>
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f32> {
-  return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
+fn sb_load_17(offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)));
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f32> {
-  return mat2x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)));
+fn sb_load_18(offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)));
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f32> {
-  return mat2x4<f32>(tint_symbol_13(buffer, (offset + 0u)), tint_symbol_13(buffer, (offset + 16u)));
+fn sb_load_19(offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)));
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_load_20(offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)), sb_load_5((offset + 16u)));
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f32> {
-  return mat3x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)));
+fn sb_load_21(offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)), sb_load_9((offset + 32u)));
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f32> {
-  return mat3x4<f32>(tint_symbol_13(buffer, (offset + 0u)), tint_symbol_13(buffer, (offset + 16u)), tint_symbol_13(buffer, (offset + 32u)));
+fn sb_load_22(offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)), sb_load_13((offset + 32u)));
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_load_23(offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)), sb_load_5((offset + 16u)), sb_load_5((offset + 24u)));
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f32> {
-  return mat4x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)), tint_symbol_9(buffer, (offset + 48u)));
+fn sb_load_24(offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)), sb_load_9((offset + 32u)), sb_load_9((offset + 48u)));
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f32> {
-  return mat4x4<f32>(tint_symbol_13(buffer, (offset + 0u)), tint_symbol_13(buffer, (offset + 16u)), tint_symbol_13(buffer, (offset + 32u)), tint_symbol_13(buffer, (offset + 48u)));
+fn sb_load_25(offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)), sb_load_13((offset + 32u)), sb_load_13((offset + 48u)));
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f16> {
-  return mat2x2<f16>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 4u)));
+fn sb_load_26(offset : u32) -> mat2x2<f16> {
+  return mat2x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)));
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f16> {
-  return mat2x3<f16>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 8u)));
+fn sb_load_27(offset : u32) -> mat2x3<f16> {
+  return mat2x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)));
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f16> {
-  return mat2x4<f16>(tint_symbol_16(buffer, (offset + 0u)), tint_symbol_16(buffer, (offset + 8u)));
+fn sb_load_28(offset : u32) -> mat2x4<f16> {
+  return mat2x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)));
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f16> {
-  return mat3x2<f16>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 4u)), tint_symbol_8(buffer, (offset + 8u)));
+fn sb_load_29(offset : u32) -> mat3x2<f16> {
+  return mat3x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)), sb_load_8((offset + 8u)));
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f16> {
-  return mat3x3<f16>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 8u)), tint_symbol_12(buffer, (offset + 16u)));
+fn sb_load_30(offset : u32) -> mat3x3<f16> {
+  return mat3x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)), sb_load_12((offset + 16u)));
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f16> {
-  return mat3x4<f16>(tint_symbol_16(buffer, (offset + 0u)), tint_symbol_16(buffer, (offset + 8u)), tint_symbol_16(buffer, (offset + 16u)));
+fn sb_load_31(offset : u32) -> mat3x4<f16> {
+  return mat3x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)), sb_load_16((offset + 16u)));
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f16> {
-  return mat4x2<f16>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 4u)), tint_symbol_8(buffer, (offset + 8u)), tint_symbol_8(buffer, (offset + 12u)));
+fn sb_load_32(offset : u32) -> mat4x2<f16> {
+  return mat4x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)), sb_load_8((offset + 8u)), sb_load_8((offset + 12u)));
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f16> {
-  return mat4x3<f16>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 8u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 24u)));
+fn sb_load_33(offset : u32) -> mat4x3<f16> {
+  return mat4x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)), sb_load_12((offset + 16u)), sb_load_12((offset + 24u)));
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f16> {
-  return mat4x4<f16>(tint_symbol_16(buffer, (offset + 0u)), tint_symbol_16(buffer, (offset + 8u)), tint_symbol_16(buffer, (offset + 16u)), tint_symbol_16(buffer, (offset + 24u)));
+fn sb_load_34(offset : u32) -> mat4x4<f16> {
+  return mat4x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)), sb_load_16((offset + 16u)), sb_load_16((offset + 24u)));
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f32>, 2u> {
+fn sb_load_35(offset : u32) -> array<vec3<f32>, 2u> {
   var arr : array<vec3<f32>, 2u>;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    arr[i] = tint_symbol_9(buffer, (offset + (i * 16u)));
+    arr[i] = sb_load_9((offset + (i * 16u)));
   }
   return arr;
 }
 
-fn tint_symbol_36(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<mat4x2<f16>, 2u> {
+fn sb_load_36(offset : u32) -> array<mat4x2<f16>, 2u> {
   var arr_1 : array<mat4x2<f16>, 2u>;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    arr_1[i_1] = tint_symbol_32(buffer, (offset + (i_1 * 16u)));
+    arr_1[i_1] = sb_load_32((offset + (i_1 * 16u)));
   }
   return arr_1;
 }
 
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> SB {
-  return SB(tint_symbol_1(buffer, (offset + 0u)), tint_symbol_2(buffer, (offset + 4u)), tint_symbol_3(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 12u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_6(buffer, (offset + 24u)), tint_symbol_7(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 40u)), tint_symbol_9(buffer, (offset + 48u)), tint_symbol_10(buffer, (offset + 64u)), tint_symbol_11(buffer, (offset + 80u)), tint_symbol_12(buffer, (offset + 96u)), tint_symbol_13(buffer, (offset + 112u)), tint_symbol_14(buffer, (offset + 128u)), tint_symbol_15(buffer, (offset + 144u)), tint_symbol_16(buffer, (offset + 160u)), tint_symbol_17(buffer, (offset + 168u)), tint_symbol_18(buffer, (offset + 192u)), tint_symbol_19(buffer, (offset + 224u)), tint_symbol_20(buffer, (offset + 256u)), tint_symbol_21(buffer, (offset + 288u)), tint_symbol_22(buffer, (offset + 336u)), tint_symbol_23(buffer, (offset + 384u)), tint_symbol_24(buffer, (offset + 416u)), tint_symbol_25(buffer, (offset + 480u)), tint_symbol_26(buffer, (offset + 544u)), tint_symbol_27(buffer, (offset + 552u)), tint_symbol_28(buffer, (offset + 568u)), tint_symbol_29(buffer, (offset + 584u)), tint_symbol_30(buffer, (offset + 600u)), tint_symbol_31(buffer, (offset + 624u)), tint_symbol_32(buffer, (offset + 648u)), tint_symbol_33(buffer, (offset + 664u)), tint_symbol_34(buffer, (offset + 696u)), tint_symbol_35(buffer, (offset + 736u)), tint_symbol_36(buffer, (offset + 768u)));
+fn sb_load(offset : u32) -> SB {
+  return SB(sb_load_1((offset + 0u)), sb_load_2((offset + 4u)), sb_load_3((offset + 8u)), sb_load_4((offset + 12u)), sb_load_5((offset + 16u)), sb_load_6((offset + 24u)), sb_load_7((offset + 32u)), sb_load_8((offset + 40u)), sb_load_9((offset + 48u)), sb_load_10((offset + 64u)), sb_load_11((offset + 80u)), sb_load_12((offset + 96u)), sb_load_13((offset + 112u)), sb_load_14((offset + 128u)), sb_load_15((offset + 144u)), sb_load_16((offset + 160u)), sb_load_17((offset + 168u)), sb_load_18((offset + 192u)), sb_load_19((offset + 224u)), sb_load_20((offset + 256u)), sb_load_21((offset + 288u)), sb_load_22((offset + 336u)), sb_load_23((offset + 384u)), sb_load_24((offset + 416u)), sb_load_25((offset + 480u)), sb_load_26((offset + 544u)), sb_load_27((offset + 552u)), sb_load_28((offset + 568u)), sb_load_29((offset + 584u)), sb_load_30((offset + 600u)), sb_load_31((offset + 624u)), sb_load_32((offset + 648u)), sb_load_33((offset + 664u)), sb_load_34((offset + 696u)), sb_load_35((offset + 736u)), sb_load_36((offset + 768u)));
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  var x : SB = tint_symbol(&(sb), 0u);
+  var x : SB = sb_load(0u);
 }
 )";
 
@@ -2290,148 +2290,148 @@
 enable f16;
 
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load_1(offset : u32) -> f32
 
 @internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
+fn sb_load_2(offset : u32) -> i32
 
 @internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
+fn sb_load_3(offset : u32) -> u32
 
 @internal(intrinsic_load_storage_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f16
+fn sb_load_4(offset : u32) -> f16
 
 @internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f32>
+fn sb_load_5(offset : u32) -> vec2<f32>
 
 @internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<i32>
+fn sb_load_6(offset : u32) -> vec2<i32>
 
 @internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<u32>
+fn sb_load_7(offset : u32) -> vec2<u32>
 
 @internal(intrinsic_load_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec2<f16>
+fn sb_load_8(offset : u32) -> vec2<f16>
 
 @internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f32>
+fn sb_load_9(offset : u32) -> vec3<f32>
 
 @internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<i32>
+fn sb_load_10(offset : u32) -> vec3<i32>
 
 @internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<u32>
+fn sb_load_11(offset : u32) -> vec3<u32>
 
 @internal(intrinsic_load_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec3<f16>
+fn sb_load_12(offset : u32) -> vec3<f16>
 
 @internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f32>
+fn sb_load_13(offset : u32) -> vec4<f32>
 
 @internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<i32>
+fn sb_load_14(offset : u32) -> vec4<i32>
 
 @internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<u32>
+fn sb_load_15(offset : u32) -> vec4<u32>
 
 @internal(intrinsic_load_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> vec4<f16>
+fn sb_load_16(offset : u32) -> vec4<f16>
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f32> {
-  return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
+fn sb_load_17(offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)));
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f32> {
-  return mat2x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)));
+fn sb_load_18(offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)));
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f32> {
-  return mat2x4<f32>(tint_symbol_13(buffer, (offset + 0u)), tint_symbol_13(buffer, (offset + 16u)));
+fn sb_load_19(offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)));
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_load_20(offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)), sb_load_5((offset + 16u)));
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f32> {
-  return mat3x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)));
+fn sb_load_21(offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)), sb_load_9((offset + 32u)));
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f32> {
-  return mat3x4<f32>(tint_symbol_13(buffer, (offset + 0u)), tint_symbol_13(buffer, (offset + 16u)), tint_symbol_13(buffer, (offset + 32u)));
+fn sb_load_22(offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)), sb_load_13((offset + 32u)));
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_load_23(offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)), sb_load_5((offset + 16u)), sb_load_5((offset + 24u)));
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f32> {
-  return mat4x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)), tint_symbol_9(buffer, (offset + 48u)));
+fn sb_load_24(offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)), sb_load_9((offset + 32u)), sb_load_9((offset + 48u)));
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f32> {
-  return mat4x4<f32>(tint_symbol_13(buffer, (offset + 0u)), tint_symbol_13(buffer, (offset + 16u)), tint_symbol_13(buffer, (offset + 32u)), tint_symbol_13(buffer, (offset + 48u)));
+fn sb_load_25(offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)), sb_load_13((offset + 32u)), sb_load_13((offset + 48u)));
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x2<f16> {
-  return mat2x2<f16>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 4u)));
+fn sb_load_26(offset : u32) -> mat2x2<f16> {
+  return mat2x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)));
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x3<f16> {
-  return mat2x3<f16>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 8u)));
+fn sb_load_27(offset : u32) -> mat2x3<f16> {
+  return mat2x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)));
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat2x4<f16> {
-  return mat2x4<f16>(tint_symbol_16(buffer, (offset + 0u)), tint_symbol_16(buffer, (offset + 8u)));
+fn sb_load_28(offset : u32) -> mat2x4<f16> {
+  return mat2x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)));
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x2<f16> {
-  return mat3x2<f16>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 4u)), tint_symbol_8(buffer, (offset + 8u)));
+fn sb_load_29(offset : u32) -> mat3x2<f16> {
+  return mat3x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)), sb_load_8((offset + 8u)));
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x3<f16> {
-  return mat3x3<f16>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 8u)), tint_symbol_12(buffer, (offset + 16u)));
+fn sb_load_30(offset : u32) -> mat3x3<f16> {
+  return mat3x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)), sb_load_12((offset + 16u)));
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat3x4<f16> {
-  return mat3x4<f16>(tint_symbol_16(buffer, (offset + 0u)), tint_symbol_16(buffer, (offset + 8u)), tint_symbol_16(buffer, (offset + 16u)));
+fn sb_load_31(offset : u32) -> mat3x4<f16> {
+  return mat3x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)), sb_load_16((offset + 16u)));
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x2<f16> {
-  return mat4x2<f16>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 4u)), tint_symbol_8(buffer, (offset + 8u)), tint_symbol_8(buffer, (offset + 12u)));
+fn sb_load_32(offset : u32) -> mat4x2<f16> {
+  return mat4x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)), sb_load_8((offset + 8u)), sb_load_8((offset + 12u)));
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x3<f16> {
-  return mat4x3<f16>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 8u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 24u)));
+fn sb_load_33(offset : u32) -> mat4x3<f16> {
+  return mat4x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)), sb_load_12((offset + 16u)), sb_load_12((offset + 24u)));
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> mat4x4<f16> {
-  return mat4x4<f16>(tint_symbol_16(buffer, (offset + 0u)), tint_symbol_16(buffer, (offset + 8u)), tint_symbol_16(buffer, (offset + 16u)), tint_symbol_16(buffer, (offset + 24u)));
+fn sb_load_34(offset : u32) -> mat4x4<f16> {
+  return mat4x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)), sb_load_16((offset + 16u)), sb_load_16((offset + 24u)));
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<vec3<f32>, 2u> {
+fn sb_load_35(offset : u32) -> array<vec3<f32>, 2u> {
   var arr : array<vec3<f32>, 2u>;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    arr[i] = tint_symbol_9(buffer, (offset + (i * 16u)));
+    arr[i] = sb_load_9((offset + (i * 16u)));
   }
   return arr;
 }
 
-fn tint_symbol_36(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> array<mat4x2<f16>, 2u> {
+fn sb_load_36(offset : u32) -> array<mat4x2<f16>, 2u> {
   var arr_1 : array<mat4x2<f16>, 2u>;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    arr_1[i_1] = tint_symbol_32(buffer, (offset + (i_1 * 16u)));
+    arr_1[i_1] = sb_load_32((offset + (i_1 * 16u)));
   }
   return arr_1;
 }
 
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> SB {
-  return SB(tint_symbol_1(buffer, (offset + 0u)), tint_symbol_2(buffer, (offset + 4u)), tint_symbol_3(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 12u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_6(buffer, (offset + 24u)), tint_symbol_7(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 40u)), tint_symbol_9(buffer, (offset + 48u)), tint_symbol_10(buffer, (offset + 64u)), tint_symbol_11(buffer, (offset + 80u)), tint_symbol_12(buffer, (offset + 96u)), tint_symbol_13(buffer, (offset + 112u)), tint_symbol_14(buffer, (offset + 128u)), tint_symbol_15(buffer, (offset + 144u)), tint_symbol_16(buffer, (offset + 160u)), tint_symbol_17(buffer, (offset + 168u)), tint_symbol_18(buffer, (offset + 192u)), tint_symbol_19(buffer, (offset + 224u)), tint_symbol_20(buffer, (offset + 256u)), tint_symbol_21(buffer, (offset + 288u)), tint_symbol_22(buffer, (offset + 336u)), tint_symbol_23(buffer, (offset + 384u)), tint_symbol_24(buffer, (offset + 416u)), tint_symbol_25(buffer, (offset + 480u)), tint_symbol_26(buffer, (offset + 544u)), tint_symbol_27(buffer, (offset + 552u)), tint_symbol_28(buffer, (offset + 568u)), tint_symbol_29(buffer, (offset + 584u)), tint_symbol_30(buffer, (offset + 600u)), tint_symbol_31(buffer, (offset + 624u)), tint_symbol_32(buffer, (offset + 648u)), tint_symbol_33(buffer, (offset + 664u)), tint_symbol_34(buffer, (offset + 696u)), tint_symbol_35(buffer, (offset + 736u)), tint_symbol_36(buffer, (offset + 768u)));
+fn sb_load(offset : u32) -> SB {
+  return SB(sb_load_1((offset + 0u)), sb_load_2((offset + 4u)), sb_load_3((offset + 8u)), sb_load_4((offset + 12u)), sb_load_5((offset + 16u)), sb_load_6((offset + 24u)), sb_load_7((offset + 32u)), sb_load_8((offset + 40u)), sb_load_9((offset + 48u)), sb_load_10((offset + 64u)), sb_load_11((offset + 80u)), sb_load_12((offset + 96u)), sb_load_13((offset + 112u)), sb_load_14((offset + 128u)), sb_load_15((offset + 144u)), sb_load_16((offset + 160u)), sb_load_17((offset + 168u)), sb_load_18((offset + 192u)), sb_load_19((offset + 224u)), sb_load_20((offset + 256u)), sb_load_21((offset + 288u)), sb_load_22((offset + 336u)), sb_load_23((offset + 384u)), sb_load_24((offset + 416u)), sb_load_25((offset + 480u)), sb_load_26((offset + 544u)), sb_load_27((offset + 552u)), sb_load_28((offset + 568u)), sb_load_29((offset + 584u)), sb_load_30((offset + 600u)), sb_load_31((offset + 624u)), sb_load_32((offset + 648u)), sb_load_33((offset + 664u)), sb_load_34((offset + 696u)), sb_load_35((offset + 736u)), sb_load_36((offset + 768u)));
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  var x : SB = tint_symbol(&(sb), 0u);
+  var x : SB = sb_load(0u);
 }
 
 @group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -2577,217 +2577,217 @@
 @group(0) @binding(0) var<storage, read_write> sb : SB;
 
 @internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f32)
+fn sb_store_1(offset : u32, value : f32)
 
 @internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : i32)
+fn sb_store_2(offset : u32, value : i32)
 
 @internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : u32)
+fn sb_store_3(offset : u32, value : u32)
 
 @internal(intrinsic_store_storage_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f16)
+fn sb_store_4(offset : u32, value : f16)
 
 @internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f32>)
+fn sb_store_5(offset : u32, value : vec2<f32>)
 
 @internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<i32>)
+fn sb_store_6(offset : u32, value : vec2<i32>)
 
 @internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<u32>)
+fn sb_store_7(offset : u32, value : vec2<u32>)
 
 @internal(intrinsic_store_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f16>)
+fn sb_store_8(offset : u32, value : vec2<f16>)
 
 @internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f32>)
+fn sb_store_9(offset : u32, value : vec3<f32>)
 
 @internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<i32>)
+fn sb_store_10(offset : u32, value : vec3<i32>)
 
 @internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<u32>)
+fn sb_store_11(offset : u32, value : vec3<u32>)
 
 @internal(intrinsic_store_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f16>)
+fn sb_store_12(offset : u32, value : vec3<f16>)
 
 @internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f32>)
+fn sb_store_13(offset : u32, value : vec4<f32>)
 
 @internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<i32>)
+fn sb_store_14(offset : u32, value : vec4<i32>)
 
 @internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<u32>)
+fn sb_store_15(offset : u32, value : vec4<u32>)
 
 @internal(intrinsic_store_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f16>)
+fn sb_store_16(offset : u32, value : vec4<f16>)
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f32>) {
-  tint_symbol_5(buffer, (offset + 0u), value[0u]);
-  tint_symbol_5(buffer, (offset + 8u), value[1u]);
+fn sb_store_17(offset : u32, value : mat2x2<f32>) {
+  sb_store_5((offset + 0u), value[0u]);
+  sb_store_5((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f32>) {
-  tint_symbol_9(buffer, (offset + 0u), value[0u]);
-  tint_symbol_9(buffer, (offset + 16u), value[1u]);
+fn sb_store_18(offset : u32, value : mat2x3<f32>) {
+  sb_store_9((offset + 0u), value[0u]);
+  sb_store_9((offset + 16u), value[1u]);
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f32>) {
-  tint_symbol_13(buffer, (offset + 0u), value[0u]);
-  tint_symbol_13(buffer, (offset + 16u), value[1u]);
+fn sb_store_19(offset : u32, value : mat2x4<f32>) {
+  sb_store_13((offset + 0u), value[0u]);
+  sb_store_13((offset + 16u), value[1u]);
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_store_20(offset : u32, value : mat3x2<f32>) {
+  sb_store_5((offset + 0u), value[0u]);
+  sb_store_5((offset + 8u), value[1u]);
+  sb_store_5((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f32>) {
-  tint_symbol_9(buffer, (offset + 0u), value[0u]);
-  tint_symbol_9(buffer, (offset + 16u), value[1u]);
-  tint_symbol_9(buffer, (offset + 32u), value[2u]);
+fn sb_store_21(offset : u32, value : mat3x3<f32>) {
+  sb_store_9((offset + 0u), value[0u]);
+  sb_store_9((offset + 16u), value[1u]);
+  sb_store_9((offset + 32u), value[2u]);
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f32>) {
-  tint_symbol_13(buffer, (offset + 0u), value[0u]);
-  tint_symbol_13(buffer, (offset + 16u), value[1u]);
-  tint_symbol_13(buffer, (offset + 32u), value[2u]);
+fn sb_store_22(offset : u32, value : mat3x4<f32>) {
+  sb_store_13((offset + 0u), value[0u]);
+  sb_store_13((offset + 16u), value[1u]);
+  sb_store_13((offset + 32u), value[2u]);
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_store_23(offset : u32, value : mat4x2<f32>) {
+  sb_store_5((offset + 0u), value[0u]);
+  sb_store_5((offset + 8u), value[1u]);
+  sb_store_5((offset + 16u), value[2u]);
+  sb_store_5((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f32>) {
-  tint_symbol_9(buffer, (offset + 0u), value[0u]);
-  tint_symbol_9(buffer, (offset + 16u), value[1u]);
-  tint_symbol_9(buffer, (offset + 32u), value[2u]);
-  tint_symbol_9(buffer, (offset + 48u), value[3u]);
+fn sb_store_24(offset : u32, value : mat4x3<f32>) {
+  sb_store_9((offset + 0u), value[0u]);
+  sb_store_9((offset + 16u), value[1u]);
+  sb_store_9((offset + 32u), value[2u]);
+  sb_store_9((offset + 48u), value[3u]);
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f32>) {
-  tint_symbol_13(buffer, (offset + 0u), value[0u]);
-  tint_symbol_13(buffer, (offset + 16u), value[1u]);
-  tint_symbol_13(buffer, (offset + 32u), value[2u]);
-  tint_symbol_13(buffer, (offset + 48u), value[3u]);
+fn sb_store_25(offset : u32, value : mat4x4<f32>) {
+  sb_store_13((offset + 0u), value[0u]);
+  sb_store_13((offset + 16u), value[1u]);
+  sb_store_13((offset + 32u), value[2u]);
+  sb_store_13((offset + 48u), value[3u]);
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f16>) {
-  tint_symbol_8(buffer, (offset + 0u), value[0u]);
-  tint_symbol_8(buffer, (offset + 4u), value[1u]);
+fn sb_store_26(offset : u32, value : mat2x2<f16>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 4u), value[1u]);
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f16>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 8u), value[1u]);
+fn sb_store_27(offset : u32, value : mat2x3<f16>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f16>) {
-  tint_symbol_16(buffer, (offset + 0u), value[0u]);
-  tint_symbol_16(buffer, (offset + 8u), value[1u]);
+fn sb_store_28(offset : u32, value : mat2x4<f16>) {
+  sb_store_16((offset + 0u), value[0u]);
+  sb_store_16((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f16>) {
-  tint_symbol_8(buffer, (offset + 0u), value[0u]);
-  tint_symbol_8(buffer, (offset + 4u), value[1u]);
-  tint_symbol_8(buffer, (offset + 8u), value[2u]);
+fn sb_store_29(offset : u32, value : mat3x2<f16>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 4u), value[1u]);
+  sb_store_8((offset + 8u), value[2u]);
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f16>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 8u), value[1u]);
-  tint_symbol_12(buffer, (offset + 16u), value[2u]);
+fn sb_store_30(offset : u32, value : mat3x3<f16>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 8u), value[1u]);
+  sb_store_12((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f16>) {
-  tint_symbol_16(buffer, (offset + 0u), value[0u]);
-  tint_symbol_16(buffer, (offset + 8u), value[1u]);
-  tint_symbol_16(buffer, (offset + 16u), value[2u]);
+fn sb_store_31(offset : u32, value : mat3x4<f16>) {
+  sb_store_16((offset + 0u), value[0u]);
+  sb_store_16((offset + 8u), value[1u]);
+  sb_store_16((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f16>) {
-  tint_symbol_8(buffer, (offset + 0u), value[0u]);
-  tint_symbol_8(buffer, (offset + 4u), value[1u]);
-  tint_symbol_8(buffer, (offset + 8u), value[2u]);
-  tint_symbol_8(buffer, (offset + 12u), value[3u]);
+fn sb_store_32(offset : u32, value : mat4x2<f16>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 4u), value[1u]);
+  sb_store_8((offset + 8u), value[2u]);
+  sb_store_8((offset + 12u), value[3u]);
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f16>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 8u), value[1u]);
-  tint_symbol_12(buffer, (offset + 16u), value[2u]);
-  tint_symbol_12(buffer, (offset + 24u), value[3u]);
+fn sb_store_33(offset : u32, value : mat4x3<f16>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 8u), value[1u]);
+  sb_store_12((offset + 16u), value[2u]);
+  sb_store_12((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f16>) {
-  tint_symbol_16(buffer, (offset + 0u), value[0u]);
-  tint_symbol_16(buffer, (offset + 8u), value[1u]);
-  tint_symbol_16(buffer, (offset + 16u), value[2u]);
-  tint_symbol_16(buffer, (offset + 24u), value[3u]);
+fn sb_store_34(offset : u32, value : mat4x4<f16>) {
+  sb_store_16((offset + 0u), value[0u]);
+  sb_store_16((offset + 8u), value[1u]);
+  sb_store_16((offset + 16u), value[2u]);
+  sb_store_16((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<vec3<f32>, 2u>) {
+fn sb_store_35(offset : u32, value : array<vec3<f32>, 2u>) {
   var array_1 = value;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    tint_symbol_9(buffer, (offset + (i * 16u)), array_1[i]);
+    sb_store_9((offset + (i * 16u)), array_1[i]);
   }
 }
 
-fn tint_symbol_36(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<mat4x2<f16>, 2u>) {
+fn sb_store_36(offset : u32, value : array<mat4x2<f16>, 2u>) {
   var array_2 = value;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    tint_symbol_32(buffer, (offset + (i_1 * 16u)), array_2[i_1]);
+    sb_store_32((offset + (i_1 * 16u)), array_2[i_1]);
   }
 }
 
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : SB) {
-  tint_symbol_1(buffer, (offset + 0u), value.scalar_f32);
-  tint_symbol_2(buffer, (offset + 4u), value.scalar_i32);
-  tint_symbol_3(buffer, (offset + 8u), value.scalar_u32);
-  tint_symbol_4(buffer, (offset + 12u), value.scalar_f16);
-  tint_symbol_5(buffer, (offset + 16u), value.vec2_f32);
-  tint_symbol_6(buffer, (offset + 24u), value.vec2_i32);
-  tint_symbol_7(buffer, (offset + 32u), value.vec2_u32);
-  tint_symbol_8(buffer, (offset + 40u), value.vec2_f16);
-  tint_symbol_9(buffer, (offset + 48u), value.vec3_f32);
-  tint_symbol_10(buffer, (offset + 64u), value.vec3_i32);
-  tint_symbol_11(buffer, (offset + 80u), value.vec3_u32);
-  tint_symbol_12(buffer, (offset + 96u), value.vec3_f16);
-  tint_symbol_13(buffer, (offset + 112u), value.vec4_f32);
-  tint_symbol_14(buffer, (offset + 128u), value.vec4_i32);
-  tint_symbol_15(buffer, (offset + 144u), value.vec4_u32);
-  tint_symbol_16(buffer, (offset + 160u), value.vec4_f16);
-  tint_symbol_17(buffer, (offset + 168u), value.mat2x2_f32);
-  tint_symbol_18(buffer, (offset + 192u), value.mat2x3_f32);
-  tint_symbol_19(buffer, (offset + 224u), value.mat2x4_f32);
-  tint_symbol_20(buffer, (offset + 256u), value.mat3x2_f32);
-  tint_symbol_21(buffer, (offset + 288u), value.mat3x3_f32);
-  tint_symbol_22(buffer, (offset + 336u), value.mat3x4_f32);
-  tint_symbol_23(buffer, (offset + 384u), value.mat4x2_f32);
-  tint_symbol_24(buffer, (offset + 416u), value.mat4x3_f32);
-  tint_symbol_25(buffer, (offset + 480u), value.mat4x4_f32);
-  tint_symbol_26(buffer, (offset + 544u), value.mat2x2_f16);
-  tint_symbol_27(buffer, (offset + 552u), value.mat2x3_f16);
-  tint_symbol_28(buffer, (offset + 568u), value.mat2x4_f16);
-  tint_symbol_29(buffer, (offset + 584u), value.mat3x2_f16);
-  tint_symbol_30(buffer, (offset + 600u), value.mat3x3_f16);
-  tint_symbol_31(buffer, (offset + 624u), value.mat3x4_f16);
-  tint_symbol_32(buffer, (offset + 648u), value.mat4x2_f16);
-  tint_symbol_33(buffer, (offset + 664u), value.mat4x3_f16);
-  tint_symbol_34(buffer, (offset + 696u), value.mat4x4_f16);
-  tint_symbol_35(buffer, (offset + 736u), value.arr2_vec3_f32);
-  tint_symbol_36(buffer, (offset + 768u), value.arr2_mat4x2_f16);
+fn sb_store(offset : u32, value : SB) {
+  sb_store_1((offset + 0u), value.scalar_f32);
+  sb_store_2((offset + 4u), value.scalar_i32);
+  sb_store_3((offset + 8u), value.scalar_u32);
+  sb_store_4((offset + 12u), value.scalar_f16);
+  sb_store_5((offset + 16u), value.vec2_f32);
+  sb_store_6((offset + 24u), value.vec2_i32);
+  sb_store_7((offset + 32u), value.vec2_u32);
+  sb_store_8((offset + 40u), value.vec2_f16);
+  sb_store_9((offset + 48u), value.vec3_f32);
+  sb_store_10((offset + 64u), value.vec3_i32);
+  sb_store_11((offset + 80u), value.vec3_u32);
+  sb_store_12((offset + 96u), value.vec3_f16);
+  sb_store_13((offset + 112u), value.vec4_f32);
+  sb_store_14((offset + 128u), value.vec4_i32);
+  sb_store_15((offset + 144u), value.vec4_u32);
+  sb_store_16((offset + 160u), value.vec4_f16);
+  sb_store_17((offset + 168u), value.mat2x2_f32);
+  sb_store_18((offset + 192u), value.mat2x3_f32);
+  sb_store_19((offset + 224u), value.mat2x4_f32);
+  sb_store_20((offset + 256u), value.mat3x2_f32);
+  sb_store_21((offset + 288u), value.mat3x3_f32);
+  sb_store_22((offset + 336u), value.mat3x4_f32);
+  sb_store_23((offset + 384u), value.mat4x2_f32);
+  sb_store_24((offset + 416u), value.mat4x3_f32);
+  sb_store_25((offset + 480u), value.mat4x4_f32);
+  sb_store_26((offset + 544u), value.mat2x2_f16);
+  sb_store_27((offset + 552u), value.mat2x3_f16);
+  sb_store_28((offset + 568u), value.mat2x4_f16);
+  sb_store_29((offset + 584u), value.mat3x2_f16);
+  sb_store_30((offset + 600u), value.mat3x3_f16);
+  sb_store_31((offset + 624u), value.mat3x4_f16);
+  sb_store_32((offset + 648u), value.mat4x2_f16);
+  sb_store_33((offset + 664u), value.mat4x3_f16);
+  sb_store_34((offset + 696u), value.mat4x4_f16);
+  sb_store_35((offset + 736u), value.arr2_vec3_f32);
+  sb_store_36((offset + 768u), value.arr2_mat4x2_f16);
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  tint_symbol(&(sb), 0u, SB());
+  sb_store(0u, SB());
 }
 )";
 
@@ -2851,217 +2851,217 @@
 enable f16;
 
 @internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f32)
+fn sb_store_1(offset : u32, value : f32)
 
 @internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_2(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : i32)
+fn sb_store_2(offset : u32, value : i32)
 
 @internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : u32)
+fn sb_store_3(offset : u32, value : u32)
 
 @internal(intrinsic_store_storage_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_4(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : f16)
+fn sb_store_4(offset : u32, value : f16)
 
 @internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_5(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f32>)
+fn sb_store_5(offset : u32, value : vec2<f32>)
 
 @internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<i32>)
+fn sb_store_6(offset : u32, value : vec2<i32>)
 
 @internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_7(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<u32>)
+fn sb_store_7(offset : u32, value : vec2<u32>)
 
 @internal(intrinsic_store_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_8(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec2<f16>)
+fn sb_store_8(offset : u32, value : vec2<f16>)
 
 @internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_9(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f32>)
+fn sb_store_9(offset : u32, value : vec3<f32>)
 
 @internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_10(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<i32>)
+fn sb_store_10(offset : u32, value : vec3<i32>)
 
 @internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_11(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<u32>)
+fn sb_store_11(offset : u32, value : vec3<u32>)
 
 @internal(intrinsic_store_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_12(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec3<f16>)
+fn sb_store_12(offset : u32, value : vec3<f16>)
 
 @internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_13(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f32>)
+fn sb_store_13(offset : u32, value : vec4<f32>)
 
 @internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_14(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<i32>)
+fn sb_store_14(offset : u32, value : vec4<i32>)
 
 @internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_15(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<u32>)
+fn sb_store_15(offset : u32, value : vec4<u32>)
 
 @internal(intrinsic_store_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn tint_symbol_16(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : vec4<f16>)
+fn sb_store_16(offset : u32, value : vec4<f16>)
 
-fn tint_symbol_17(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f32>) {
-  tint_symbol_5(buffer, (offset + 0u), value[0u]);
-  tint_symbol_5(buffer, (offset + 8u), value[1u]);
+fn sb_store_17(offset : u32, value : mat2x2<f32>) {
+  sb_store_5((offset + 0u), value[0u]);
+  sb_store_5((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_18(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f32>) {
-  tint_symbol_9(buffer, (offset + 0u), value[0u]);
-  tint_symbol_9(buffer, (offset + 16u), value[1u]);
+fn sb_store_18(offset : u32, value : mat2x3<f32>) {
+  sb_store_9((offset + 0u), value[0u]);
+  sb_store_9((offset + 16u), value[1u]);
 }
 
-fn tint_symbol_19(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f32>) {
-  tint_symbol_13(buffer, (offset + 0u), value[0u]);
-  tint_symbol_13(buffer, (offset + 16u), value[1u]);
+fn sb_store_19(offset : u32, value : mat2x4<f32>) {
+  sb_store_13((offset + 0u), value[0u]);
+  sb_store_13((offset + 16u), value[1u]);
 }
 
-fn tint_symbol_20(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_store_20(offset : u32, value : mat3x2<f32>) {
+  sb_store_5((offset + 0u), value[0u]);
+  sb_store_5((offset + 8u), value[1u]);
+  sb_store_5((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_21(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f32>) {
-  tint_symbol_9(buffer, (offset + 0u), value[0u]);
-  tint_symbol_9(buffer, (offset + 16u), value[1u]);
-  tint_symbol_9(buffer, (offset + 32u), value[2u]);
+fn sb_store_21(offset : u32, value : mat3x3<f32>) {
+  sb_store_9((offset + 0u), value[0u]);
+  sb_store_9((offset + 16u), value[1u]);
+  sb_store_9((offset + 32u), value[2u]);
 }
 
-fn tint_symbol_22(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f32>) {
-  tint_symbol_13(buffer, (offset + 0u), value[0u]);
-  tint_symbol_13(buffer, (offset + 16u), value[1u]);
-  tint_symbol_13(buffer, (offset + 32u), value[2u]);
+fn sb_store_22(offset : u32, value : mat3x4<f32>) {
+  sb_store_13((offset + 0u), value[0u]);
+  sb_store_13((offset + 16u), value[1u]);
+  sb_store_13((offset + 32u), value[2u]);
 }
 
-fn tint_symbol_23(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, 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 sb_store_23(offset : u32, value : mat4x2<f32>) {
+  sb_store_5((offset + 0u), value[0u]);
+  sb_store_5((offset + 8u), value[1u]);
+  sb_store_5((offset + 16u), value[2u]);
+  sb_store_5((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_24(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f32>) {
-  tint_symbol_9(buffer, (offset + 0u), value[0u]);
-  tint_symbol_9(buffer, (offset + 16u), value[1u]);
-  tint_symbol_9(buffer, (offset + 32u), value[2u]);
-  tint_symbol_9(buffer, (offset + 48u), value[3u]);
+fn sb_store_24(offset : u32, value : mat4x3<f32>) {
+  sb_store_9((offset + 0u), value[0u]);
+  sb_store_9((offset + 16u), value[1u]);
+  sb_store_9((offset + 32u), value[2u]);
+  sb_store_9((offset + 48u), value[3u]);
 }
 
-fn tint_symbol_25(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f32>) {
-  tint_symbol_13(buffer, (offset + 0u), value[0u]);
-  tint_symbol_13(buffer, (offset + 16u), value[1u]);
-  tint_symbol_13(buffer, (offset + 32u), value[2u]);
-  tint_symbol_13(buffer, (offset + 48u), value[3u]);
+fn sb_store_25(offset : u32, value : mat4x4<f32>) {
+  sb_store_13((offset + 0u), value[0u]);
+  sb_store_13((offset + 16u), value[1u]);
+  sb_store_13((offset + 32u), value[2u]);
+  sb_store_13((offset + 48u), value[3u]);
 }
 
-fn tint_symbol_26(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x2<f16>) {
-  tint_symbol_8(buffer, (offset + 0u), value[0u]);
-  tint_symbol_8(buffer, (offset + 4u), value[1u]);
+fn sb_store_26(offset : u32, value : mat2x2<f16>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 4u), value[1u]);
 }
 
-fn tint_symbol_27(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x3<f16>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 8u), value[1u]);
+fn sb_store_27(offset : u32, value : mat2x3<f16>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_28(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat2x4<f16>) {
-  tint_symbol_16(buffer, (offset + 0u), value[0u]);
-  tint_symbol_16(buffer, (offset + 8u), value[1u]);
+fn sb_store_28(offset : u32, value : mat2x4<f16>) {
+  sb_store_16((offset + 0u), value[0u]);
+  sb_store_16((offset + 8u), value[1u]);
 }
 
-fn tint_symbol_29(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x2<f16>) {
-  tint_symbol_8(buffer, (offset + 0u), value[0u]);
-  tint_symbol_8(buffer, (offset + 4u), value[1u]);
-  tint_symbol_8(buffer, (offset + 8u), value[2u]);
+fn sb_store_29(offset : u32, value : mat3x2<f16>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 4u), value[1u]);
+  sb_store_8((offset + 8u), value[2u]);
 }
 
-fn tint_symbol_30(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x3<f16>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 8u), value[1u]);
-  tint_symbol_12(buffer, (offset + 16u), value[2u]);
+fn sb_store_30(offset : u32, value : mat3x3<f16>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 8u), value[1u]);
+  sb_store_12((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_31(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat3x4<f16>) {
-  tint_symbol_16(buffer, (offset + 0u), value[0u]);
-  tint_symbol_16(buffer, (offset + 8u), value[1u]);
-  tint_symbol_16(buffer, (offset + 16u), value[2u]);
+fn sb_store_31(offset : u32, value : mat3x4<f16>) {
+  sb_store_16((offset + 0u), value[0u]);
+  sb_store_16((offset + 8u), value[1u]);
+  sb_store_16((offset + 16u), value[2u]);
 }
 
-fn tint_symbol_32(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x2<f16>) {
-  tint_symbol_8(buffer, (offset + 0u), value[0u]);
-  tint_symbol_8(buffer, (offset + 4u), value[1u]);
-  tint_symbol_8(buffer, (offset + 8u), value[2u]);
-  tint_symbol_8(buffer, (offset + 12u), value[3u]);
+fn sb_store_32(offset : u32, value : mat4x2<f16>) {
+  sb_store_8((offset + 0u), value[0u]);
+  sb_store_8((offset + 4u), value[1u]);
+  sb_store_8((offset + 8u), value[2u]);
+  sb_store_8((offset + 12u), value[3u]);
 }
 
-fn tint_symbol_33(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x3<f16>) {
-  tint_symbol_12(buffer, (offset + 0u), value[0u]);
-  tint_symbol_12(buffer, (offset + 8u), value[1u]);
-  tint_symbol_12(buffer, (offset + 16u), value[2u]);
-  tint_symbol_12(buffer, (offset + 24u), value[3u]);
+fn sb_store_33(offset : u32, value : mat4x3<f16>) {
+  sb_store_12((offset + 0u), value[0u]);
+  sb_store_12((offset + 8u), value[1u]);
+  sb_store_12((offset + 16u), value[2u]);
+  sb_store_12((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_34(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : mat4x4<f16>) {
-  tint_symbol_16(buffer, (offset + 0u), value[0u]);
-  tint_symbol_16(buffer, (offset + 8u), value[1u]);
-  tint_symbol_16(buffer, (offset + 16u), value[2u]);
-  tint_symbol_16(buffer, (offset + 24u), value[3u]);
+fn sb_store_34(offset : u32, value : mat4x4<f16>) {
+  sb_store_16((offset + 0u), value[0u]);
+  sb_store_16((offset + 8u), value[1u]);
+  sb_store_16((offset + 16u), value[2u]);
+  sb_store_16((offset + 24u), value[3u]);
 }
 
-fn tint_symbol_35(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<vec3<f32>, 2u>) {
+fn sb_store_35(offset : u32, value : array<vec3<f32>, 2u>) {
   var array_1 = value;
   for(var i = 0u; (i < 2u); i = (i + 1u)) {
-    tint_symbol_9(buffer, (offset + (i * 16u)), array_1[i]);
+    sb_store_9((offset + (i * 16u)), array_1[i]);
   }
 }
 
-fn tint_symbol_36(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : array<mat4x2<f16>, 2u>) {
+fn sb_store_36(offset : u32, value : array<mat4x2<f16>, 2u>) {
   var array_2 = value;
   for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
-    tint_symbol_32(buffer, (offset + (i_1 * 16u)), array_2[i_1]);
+    sb_store_32((offset + (i_1 * 16u)), array_2[i_1]);
   }
 }
 
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, value : SB) {
-  tint_symbol_1(buffer, (offset + 0u), value.scalar_f32);
-  tint_symbol_2(buffer, (offset + 4u), value.scalar_i32);
-  tint_symbol_3(buffer, (offset + 8u), value.scalar_u32);
-  tint_symbol_4(buffer, (offset + 12u), value.scalar_f16);
-  tint_symbol_5(buffer, (offset + 16u), value.vec2_f32);
-  tint_symbol_6(buffer, (offset + 24u), value.vec2_i32);
-  tint_symbol_7(buffer, (offset + 32u), value.vec2_u32);
-  tint_symbol_8(buffer, (offset + 40u), value.vec2_f16);
-  tint_symbol_9(buffer, (offset + 48u), value.vec3_f32);
-  tint_symbol_10(buffer, (offset + 64u), value.vec3_i32);
-  tint_symbol_11(buffer, (offset + 80u), value.vec3_u32);
-  tint_symbol_12(buffer, (offset + 96u), value.vec3_f16);
-  tint_symbol_13(buffer, (offset + 112u), value.vec4_f32);
-  tint_symbol_14(buffer, (offset + 128u), value.vec4_i32);
-  tint_symbol_15(buffer, (offset + 144u), value.vec4_u32);
-  tint_symbol_16(buffer, (offset + 160u), value.vec4_f16);
-  tint_symbol_17(buffer, (offset + 168u), value.mat2x2_f32);
-  tint_symbol_18(buffer, (offset + 192u), value.mat2x3_f32);
-  tint_symbol_19(buffer, (offset + 224u), value.mat2x4_f32);
-  tint_symbol_20(buffer, (offset + 256u), value.mat3x2_f32);
-  tint_symbol_21(buffer, (offset + 288u), value.mat3x3_f32);
-  tint_symbol_22(buffer, (offset + 336u), value.mat3x4_f32);
-  tint_symbol_23(buffer, (offset + 384u), value.mat4x2_f32);
-  tint_symbol_24(buffer, (offset + 416u), value.mat4x3_f32);
-  tint_symbol_25(buffer, (offset + 480u), value.mat4x4_f32);
-  tint_symbol_26(buffer, (offset + 544u), value.mat2x2_f16);
-  tint_symbol_27(buffer, (offset + 552u), value.mat2x3_f16);
-  tint_symbol_28(buffer, (offset + 568u), value.mat2x4_f16);
-  tint_symbol_29(buffer, (offset + 584u), value.mat3x2_f16);
-  tint_symbol_30(buffer, (offset + 600u), value.mat3x3_f16);
-  tint_symbol_31(buffer, (offset + 624u), value.mat3x4_f16);
-  tint_symbol_32(buffer, (offset + 648u), value.mat4x2_f16);
-  tint_symbol_33(buffer, (offset + 664u), value.mat4x3_f16);
-  tint_symbol_34(buffer, (offset + 696u), value.mat4x4_f16);
-  tint_symbol_35(buffer, (offset + 736u), value.arr2_vec3_f32);
-  tint_symbol_36(buffer, (offset + 768u), value.arr2_mat4x2_f16);
+fn sb_store(offset : u32, value : SB) {
+  sb_store_1((offset + 0u), value.scalar_f32);
+  sb_store_2((offset + 4u), value.scalar_i32);
+  sb_store_3((offset + 8u), value.scalar_u32);
+  sb_store_4((offset + 12u), value.scalar_f16);
+  sb_store_5((offset + 16u), value.vec2_f32);
+  sb_store_6((offset + 24u), value.vec2_i32);
+  sb_store_7((offset + 32u), value.vec2_u32);
+  sb_store_8((offset + 40u), value.vec2_f16);
+  sb_store_9((offset + 48u), value.vec3_f32);
+  sb_store_10((offset + 64u), value.vec3_i32);
+  sb_store_11((offset + 80u), value.vec3_u32);
+  sb_store_12((offset + 96u), value.vec3_f16);
+  sb_store_13((offset + 112u), value.vec4_f32);
+  sb_store_14((offset + 128u), value.vec4_i32);
+  sb_store_15((offset + 144u), value.vec4_u32);
+  sb_store_16((offset + 160u), value.vec4_f16);
+  sb_store_17((offset + 168u), value.mat2x2_f32);
+  sb_store_18((offset + 192u), value.mat2x3_f32);
+  sb_store_19((offset + 224u), value.mat2x4_f32);
+  sb_store_20((offset + 256u), value.mat3x2_f32);
+  sb_store_21((offset + 288u), value.mat3x3_f32);
+  sb_store_22((offset + 336u), value.mat3x4_f32);
+  sb_store_23((offset + 384u), value.mat4x2_f32);
+  sb_store_24((offset + 416u), value.mat4x3_f32);
+  sb_store_25((offset + 480u), value.mat4x4_f32);
+  sb_store_26((offset + 544u), value.mat2x2_f16);
+  sb_store_27((offset + 552u), value.mat2x3_f16);
+  sb_store_28((offset + 568u), value.mat2x4_f16);
+  sb_store_29((offset + 584u), value.mat3x2_f16);
+  sb_store_30((offset + 600u), value.mat3x3_f16);
+  sb_store_31((offset + 624u), value.mat3x4_f16);
+  sb_store_32((offset + 648u), value.mat4x2_f16);
+  sb_store_33((offset + 664u), value.mat4x3_f16);
+  sb_store_34((offset + 696u), value.mat4x4_f16);
+  sb_store_35((offset + 736u), value.arr2_vec3_f32);
+  sb_store_36((offset + 768u), value.arr2_mat4x2_f16);
 }
 
 @compute @workgroup_size(1)
 fn main() {
-  tint_symbol(&(sb), 0u, SB());
+  sb_store(0u, SB());
 }
 
 @group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -3172,11 +3172,11 @@
 @group(0) @binding(0) var<storage, read_write> sb : SB;
 
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load(offset : u32) -> f32
 
 @compute @workgroup_size(1)
 fn main() {
-  var x : f32 = tint_symbol(&(sb), 712u);
+  var x : f32 = sb_load(712u);
 }
 )";
 
@@ -3222,11 +3222,11 @@
 
     auto* expect = R"(
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load(offset : u32) -> f32
 
 @compute @workgroup_size(1)
 fn main() {
-  var x : f32 = tint_symbol(&(sb), 712u);
+  var x : f32 = sb_load(712u);
 }
 
 @group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -3308,14 +3308,14 @@
 @group(0) @binding(0) var<storage, read_write> sb : SB;
 
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load(offset : u32) -> f32
 
 @compute @workgroup_size(1)
 fn main() {
   var i : i32 = 4;
   var j : u32 = 1u;
   var k : i32 = 2;
-  var x : f32 = tint_symbol(&(sb), (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+  var x : f32 = sb_load((((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
 }
 )";
 
@@ -3357,14 +3357,14 @@
 
     auto* expect = R"(
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load(offset : u32) -> f32
 
 @compute @workgroup_size(1)
 fn main() {
   var i : i32 = 4;
   var j : u32 = 1u;
   var k : i32 = 2;
-  var x : f32 = tint_symbol(&(sb), (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+  var x : f32 = sb_load((((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
 }
 
 @group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -3401,9 +3401,9 @@
   c : i32,
 };
 
-type A1 = S1;
+alias A1 = S1;
 
-type A1_Array = array<S1, 3>;
+alias A1_Array = array<S1, 3>;
 
 struct S2 {
   a : i32,
@@ -3411,9 +3411,9 @@
   c : i32,
 };
 
-type A2 = S2;
+alias A2 = S2;
 
-type A2_Array = array<S2>;
+alias A2_Array = array<S2>;
 
 struct SB {
   @size(128)
@@ -3462,14 +3462,14 @@
 @group(0) @binding(0) var<storage, read_write> sb : SB;
 
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load(offset : u32) -> f32
 
 @compute @workgroup_size(1)
 fn main() {
   var i : i32 = 4;
   var j : u32 = 1u;
   var k : i32 = 2;
-  var x : f32 = tint_symbol(&(sb), (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+  var x : f32 = sb_load((((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
 }
 )";
 
@@ -3496,9 +3496,9 @@
   b : A2_Array,
 };
 
-type A2_Array = array<S2>;
+alias A2_Array = array<S2>;
 
-type A2 = S2;
+alias A2 = S2;
 
 struct S2 {
   a : i32,
@@ -3506,9 +3506,9 @@
   c : i32,
 };
 
-type A1 = S1;
+alias A1 = S1;
 
-type A1_Array = array<S1, 3>;
+alias A1_Array = array<S1, 3>;
 
 struct S1 {
   a : i32,
@@ -3519,14 +3519,14 @@
 
     auto* expect = R"(
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> f32
+fn sb_load(offset : u32) -> f32
 
 @compute @workgroup_size(1)
 fn main() {
   var i : i32 = 4;
   var j : u32 = 1u;
   var k : i32 = 2;
-  var x : f32 = tint_symbol(&(sb), (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+  var x : f32 = sb_load((((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
 }
 
 @group(0) @binding(0) var<storage, read_write> sb : SB;
@@ -3611,34 +3611,34 @@
 @group(0) @binding(0) var<storage, read_write> sb : SB;
 
 @internal(intrinsic_atomic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicStore(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32)
+fn sbatomicStore(offset : u32, param_1 : i32)
 
 @internal(intrinsic_atomic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicLoad(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
+fn sbatomicLoad(offset : u32) -> i32
 
 @internal(intrinsic_atomic_add_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAdd(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicAdd(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_sub_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicSub(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicSub(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_max_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMax(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicMax(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_min_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMin(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicMin(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_and_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAnd(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicAnd(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_or_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicOr(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicOr(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_xor_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicXor(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicXor(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_exchange_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicExchange(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicExchange(offset : u32, param_1 : i32) -> i32
 
 struct atomic_compare_exchange_weak_ret_type {
   old_value : i32,
@@ -3646,37 +3646,37 @@
 }
 
 @internal(intrinsic_atomic_compare_exchange_weak_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicCompareExchangeWeak(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32, param_2 : i32) -> atomic_compare_exchange_weak_ret_type
+fn sbatomicCompareExchangeWeak(offset : u32, param_1 : i32, param_2 : i32) -> atomic_compare_exchange_weak_ret_type
 
 @internal(intrinsic_atomic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicStore_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32)
+fn sbatomicStore_1(offset : u32, param_1 : u32)
 
 @internal(intrinsic_atomic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicLoad_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
+fn sbatomicLoad_1(offset : u32) -> u32
 
 @internal(intrinsic_atomic_add_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAdd_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicAdd_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_sub_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicSub_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicSub_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_max_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMax_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicMax_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_min_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMin_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicMin_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_and_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAnd_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicAnd_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_or_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicOr_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicOr_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_xor_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicXor_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicXor_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_exchange_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicExchange_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicExchange_1(offset : u32, param_1 : u32) -> u32
 
 struct atomic_compare_exchange_weak_ret_type_1 {
   old_value : u32,
@@ -3684,32 +3684,32 @@
 }
 
 @internal(intrinsic_atomic_compare_exchange_weak_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicCompareExchangeWeak_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32, param_2 : u32) -> atomic_compare_exchange_weak_ret_type_1
+fn sbatomicCompareExchangeWeak_1(offset : u32, param_1 : u32, param_2 : u32) -> atomic_compare_exchange_weak_ret_type_1
 
 @compute @workgroup_size(1)
 fn main() {
-  tint_atomicStore(&(sb), 16u, 123);
-  tint_atomicLoad(&(sb), 16u);
-  tint_atomicAdd(&(sb), 16u, 123);
-  tint_atomicSub(&(sb), 16u, 123);
-  tint_atomicMax(&(sb), 16u, 123);
-  tint_atomicMin(&(sb), 16u, 123);
-  tint_atomicAnd(&(sb), 16u, 123);
-  tint_atomicOr(&(sb), 16u, 123);
-  tint_atomicXor(&(sb), 16u, 123);
-  tint_atomicExchange(&(sb), 16u, 123);
-  tint_atomicCompareExchangeWeak(&(sb), 16u, 123, 345);
-  tint_atomicStore_1(&(sb), 20u, 123u);
-  tint_atomicLoad_1(&(sb), 20u);
-  tint_atomicAdd_1(&(sb), 20u, 123u);
-  tint_atomicSub_1(&(sb), 20u, 123u);
-  tint_atomicMax_1(&(sb), 20u, 123u);
-  tint_atomicMin_1(&(sb), 20u, 123u);
-  tint_atomicAnd_1(&(sb), 20u, 123u);
-  tint_atomicOr_1(&(sb), 20u, 123u);
-  tint_atomicXor_1(&(sb), 20u, 123u);
-  tint_atomicExchange_1(&(sb), 20u, 123u);
-  tint_atomicCompareExchangeWeak_1(&(sb), 20u, 123u, 345u);
+  sbatomicStore(16u, 123);
+  sbatomicLoad(16u);
+  sbatomicAdd(16u, 123);
+  sbatomicSub(16u, 123);
+  sbatomicMax(16u, 123);
+  sbatomicMin(16u, 123);
+  sbatomicAnd(16u, 123);
+  sbatomicOr(16u, 123);
+  sbatomicXor(16u, 123);
+  sbatomicExchange(16u, 123);
+  sbatomicCompareExchangeWeak(16u, 123, 345);
+  sbatomicStore_1(20u, 123u);
+  sbatomicLoad_1(20u);
+  sbatomicAdd_1(20u, 123u);
+  sbatomicSub_1(20u, 123u);
+  sbatomicMax_1(20u, 123u);
+  sbatomicMin_1(20u, 123u);
+  sbatomicAnd_1(20u, 123u);
+  sbatomicOr_1(20u, 123u);
+  sbatomicXor_1(20u, 123u);
+  sbatomicExchange_1(20u, 123u);
+  sbatomicCompareExchangeWeak_1(20u, 123u, 345u);
 }
 )";
 
@@ -3758,34 +3758,34 @@
 
     auto* expect = R"(
 @internal(intrinsic_atomic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicStore(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32)
+fn sbatomicStore(offset : u32, param_1 : i32)
 
 @internal(intrinsic_atomic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicLoad(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> i32
+fn sbatomicLoad(offset : u32) -> i32
 
 @internal(intrinsic_atomic_add_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAdd(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicAdd(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_sub_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicSub(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicSub(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_max_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMax(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicMax(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_min_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMin(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicMin(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_and_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAnd(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicAnd(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_or_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicOr(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicOr(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_xor_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicXor(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicXor(offset : u32, param_1 : i32) -> i32
 
 @internal(intrinsic_atomic_exchange_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicExchange(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32) -> i32
+fn sbatomicExchange(offset : u32, param_1 : i32) -> i32
 
 struct atomic_compare_exchange_weak_ret_type {
   old_value : i32,
@@ -3793,37 +3793,37 @@
 }
 
 @internal(intrinsic_atomic_compare_exchange_weak_storage_i32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicCompareExchangeWeak(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : i32, param_2 : i32) -> atomic_compare_exchange_weak_ret_type
+fn sbatomicCompareExchangeWeak(offset : u32, param_1 : i32, param_2 : i32) -> atomic_compare_exchange_weak_ret_type
 
 @internal(intrinsic_atomic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicStore_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32)
+fn sbatomicStore_1(offset : u32, param_1 : u32)
 
 @internal(intrinsic_atomic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicLoad_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32) -> u32
+fn sbatomicLoad_1(offset : u32) -> u32
 
 @internal(intrinsic_atomic_add_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAdd_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicAdd_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_sub_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicSub_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicSub_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_max_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMax_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicMax_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_min_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicMin_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicMin_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_and_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicAnd_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicAnd_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_or_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicOr_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicOr_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_xor_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicXor_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicXor_1(offset : u32, param_1 : u32) -> u32
 
 @internal(intrinsic_atomic_exchange_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicExchange_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32) -> u32
+fn sbatomicExchange_1(offset : u32, param_1 : u32) -> u32
 
 struct atomic_compare_exchange_weak_ret_type_1 {
   old_value : u32,
@@ -3831,32 +3831,32 @@
 }
 
 @internal(intrinsic_atomic_compare_exchange_weak_storage_u32) @internal(disable_validation__function_has_no_body)
-fn tint_atomicCompareExchangeWeak_1(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read_write>, offset : u32, param_1 : u32, param_2 : u32) -> atomic_compare_exchange_weak_ret_type_1
+fn sbatomicCompareExchangeWeak_1(offset : u32, param_1 : u32, param_2 : u32) -> atomic_compare_exchange_weak_ret_type_1
 
 @compute @workgroup_size(1)
 fn main() {
-  tint_atomicStore(&(sb), 16u, 123);
-  tint_atomicLoad(&(sb), 16u);
-  tint_atomicAdd(&(sb), 16u, 123);
-  tint_atomicSub(&(sb), 16u, 123);
-  tint_atomicMax(&(sb), 16u, 123);
-  tint_atomicMin(&(sb), 16u, 123);
-  tint_atomicAnd(&(sb), 16u, 123);
-  tint_atomicOr(&(sb), 16u, 123);
-  tint_atomicXor(&(sb), 16u, 123);
-  tint_atomicExchange(&(sb), 16u, 123);
-  tint_atomicCompareExchangeWeak(&(sb), 16u, 123, 345);
-  tint_atomicStore_1(&(sb), 20u, 123u);
-  tint_atomicLoad_1(&(sb), 20u);
-  tint_atomicAdd_1(&(sb), 20u, 123u);
-  tint_atomicSub_1(&(sb), 20u, 123u);
-  tint_atomicMax_1(&(sb), 20u, 123u);
-  tint_atomicMin_1(&(sb), 20u, 123u);
-  tint_atomicAnd_1(&(sb), 20u, 123u);
-  tint_atomicOr_1(&(sb), 20u, 123u);
-  tint_atomicXor_1(&(sb), 20u, 123u);
-  tint_atomicExchange_1(&(sb), 20u, 123u);
-  tint_atomicCompareExchangeWeak_1(&(sb), 20u, 123u, 345u);
+  sbatomicStore(16u, 123);
+  sbatomicLoad(16u);
+  sbatomicAdd(16u, 123);
+  sbatomicSub(16u, 123);
+  sbatomicMax(16u, 123);
+  sbatomicMin(16u, 123);
+  sbatomicAnd(16u, 123);
+  sbatomicOr(16u, 123);
+  sbatomicXor(16u, 123);
+  sbatomicExchange(16u, 123);
+  sbatomicCompareExchangeWeak(16u, 123, 345);
+  sbatomicStore_1(20u, 123u);
+  sbatomicLoad_1(20u);
+  sbatomicAdd_1(20u, 123u);
+  sbatomicSub_1(20u, 123u);
+  sbatomicMax_1(20u, 123u);
+  sbatomicMin_1(20u, 123u);
+  sbatomicAnd_1(20u, 123u);
+  sbatomicOr_1(20u, 123u);
+  sbatomicXor_1(20u, 123u);
+  sbatomicExchange_1(20u, 123u);
+  sbatomicCompareExchangeWeak_1(20u, 123u, 345u);
 }
 
 @group(0) @binding(0) var<storage, read_write> sb : SB;
diff --git a/src/tint/transform/decompose_strided_array.cc b/src/tint/transform/decompose_strided_array.cc
index e92b85e..838948e 100644
--- a/src/tint/transform/decompose_strided_array.cc
+++ b/src/tint/transform/decompose_strided_array.cc
@@ -22,7 +22,7 @@
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/type_expression.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
 #include "src/tint/sem/value_expression.h"
 #include "src/tint/transform/simplify_pointers.h"
 #include "src/tint/utils/hash.h"
@@ -134,18 +134,16 @@
         return nullptr;
     });
 
-    // Find all array type initializer expressions for array types that have had
-    // their element changed to a single field structure. These initializers are
-    // adjusted to wrap each of the arguments with an additional initializer for
-    // the new element structure type.
-    // Example:
+    // Find all constructor expressions for array types that have had their element changed to a
+    // single field structure. These constructors are adjusted to wrap each of the arguments with an
+    // additional initializer for the new element structure type. Example:
     //   `@stride(32) array<i32, 3>(1, 2, 3)`
     // ->
     //   `array<strided_arr, 3>(strided_arr(1), strided_arr(2), strided_arr(3))`
     ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
         if (!expr->args.IsEmpty()) {
             if (auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>()) {
-                if (auto* ctor = call->Target()->As<sem::TypeInitializer>()) {
+                if (auto* ctor = call->Target()->As<sem::ValueConstructor>()) {
                     if (auto* arr = ctor->ReturnType()->As<type::Array>()) {
                         // Begin by cloning the array initializer type or name
                         // If this is an unaliased array, this may add a new entry to
diff --git a/src/tint/transform/decompose_strided_array_test.cc b/src/tint/transform/decompose_strided_array_test.cc
index 72bc1b1..54c00b7 100644
--- a/src/tint/transform/decompose_strided_array_test.cc
+++ b/src/tint/transform/decompose_strided_array_test.cc
@@ -39,7 +39,7 @@
     // var<private> arr : array<f32, 4u>
 
     ProgramBuilder b;
-    b.GlobalVar("arr", b.ty.array<f32, 4u>(), type::AddressSpace::kPrivate);
+    b.GlobalVar("arr", b.ty.array<f32, 4u>(), builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
@@ -51,7 +51,7 @@
                 b.ty.array<f32, 4u>(utils::Vector{
                     b.Stride(4),
                 }),
-                type::AddressSpace::kPrivate);
+                builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
@@ -63,7 +63,7 @@
                 b.ty.array<f32, 4u>(utils::Vector{
                     b.Stride(16),
                 }),
-                type::AddressSpace::kPrivate);
+                builtin::AddressSpace::kPrivate);
     EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
@@ -90,7 +90,7 @@
                 b.ty.array<f32, 4u>(utils::Vector{
                     b.Stride(4),
                 }),
-                type::AddressSpace::kPrivate);
+                builtin::AddressSpace::kPrivate);
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("a",
@@ -134,7 +134,7 @@
                 b.ty.array<f32, 4u>(utils::Vector{
                     b.Stride(32),
                 }),
-                type::AddressSpace::kPrivate);
+                builtin::AddressSpace::kPrivate);
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("a",
@@ -184,7 +184,7 @@
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
                                                                b.Stride(32),
                                                            }))});
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("a",
@@ -239,7 +239,7 @@
                                                                       utils::Vector{
                                                                           b.Stride(16),
                                                                       }))});
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func(
         "f", utils::Empty, b.ty.void_(),
         utils::Vector{
@@ -292,7 +292,7 @@
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
                                                                b.Stride(32),
                                                            }))});
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("a",
@@ -346,7 +346,7 @@
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
                                                                b.Stride(4),
                                                            }))});
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("a",
@@ -396,7 +396,7 @@
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
                                                                b.Stride(32),
                                                            }))});
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -458,7 +458,7 @@
                                                      b.Stride(4),
                                                  })),
                                });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -516,7 +516,7 @@
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
                                                                b.Stride(32),
                                                            }))});
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -582,7 +582,7 @@
                        b.Stride(32),
                    }));
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty("ARR"))});
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -658,7 +658,7 @@
                              b.Stride(128),
                          }));
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty("ARR_B"))});
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
diff --git a/src/tint/transform/decompose_strided_matrix.cc b/src/tint/transform/decompose_strided_matrix.cc
index 4642c57..dd03dc2 100644
--- a/src/tint/transform/decompose_strided_matrix.cc
+++ b/src/tint/transform/decompose_strided_matrix.cc
@@ -74,8 +74,8 @@
     for (auto* node : src->ASTNodes().Objects()) {
         if (auto* str = node->As<ast::Struct>()) {
             auto* str_ty = src->Sem().Get(str);
-            if (!str_ty->UsedAs(type::AddressSpace::kUniform) &&
-                !str_ty->UsedAs(type::AddressSpace::kStorage)) {
+            if (!str_ty->UsedAs(builtin::AddressSpace::kUniform) &&
+                !str_ty->UsedAs(builtin::AddressSpace::kStorage)) {
                 continue;
             }
             for (auto* member : str_ty->Members()) {
diff --git a/src/tint/transform/decompose_strided_matrix_test.cc b/src/tint/transform/decompose_strided_matrix_test.cc
index e097acb..12ca02e 100644
--- a/src/tint/transform/decompose_strided_matrix_test.cc
+++ b/src/tint/transform/decompose_strided_matrix_test.cc
@@ -76,7 +76,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
@@ -133,7 +133,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func(
         "f", utils::Empty, b.ty.void_(),
         utils::Vector{
@@ -187,7 +187,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
@@ -241,7 +241,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -299,7 +299,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func(
         "f", utils::Empty, b.ty.void_(),
@@ -354,7 +354,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -413,7 +413,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -473,7 +473,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -545,7 +545,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kPrivate);
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kPrivate);
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
@@ -599,7 +599,7 @@
                               b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
                           }),
              });
-    b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kPrivate);
+    b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kPrivate);
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Assign(b.MemberAccessor("s", "m"),
diff --git a/src/tint/transform/demote_to_helper.cc b/src/tint/transform/demote_to_helper.cc
index dc5384b..ac3c15e 100644
--- a/src/tint/transform/demote_to_helper.cc
+++ b/src/tint/transform/demote_to_helper.cc
@@ -81,7 +81,7 @@
 
     // Create a module-scope flag that indicates whether the current invocation has been discarded.
     auto flag = b.Symbols().New("tint_discarded");
-    b.GlobalVar(flag, type::AddressSpace::kPrivate, b.Expr(false));
+    b.GlobalVar(flag, builtin::AddressSpace::kPrivate, b.Expr(false));
 
     // Replace all discard statements with a statement that marks the invocation as discarded.
     ctx.ReplaceAll([&](const ast::DiscardStatement*) -> const ast::Statement* {
@@ -125,12 +125,12 @@
                 // Skip writes to invocation-private address spaces.
                 auto* ref = sem.GetVal(assign->lhs)->Type()->As<type::Reference>();
                 switch (ref->AddressSpace()) {
-                    case type::AddressSpace::kStorage:
+                    case builtin::AddressSpace::kStorage:
                         // Need to mask these.
                         break;
-                    case type::AddressSpace::kFunction:
-                    case type::AddressSpace::kPrivate:
-                    case type::AddressSpace::kOut:
+                    case builtin::AddressSpace::kFunction:
+                    case builtin::AddressSpace::kPrivate:
+                    case builtin::AddressSpace::kOut:
                         // Skip these.
                         return;
                     default:
diff --git a/src/tint/transform/direct_variable_access.cc b/src/tint/transform/direct_variable_access.cc
index 8ae3e22..a6ef9d8 100644
--- a/src/tint/transform/direct_variable_access.cc
+++ b/src/tint/transform/direct_variable_access.cc
@@ -50,7 +50,7 @@
     /// function-scope variable ('function'), or pointer parameter in the source program.
     tint::sem::Variable const* variable = nullptr;
     /// The address space of the variable or pointer type.
-    tint::type::AddressSpace address_space = tint::type::AddressSpace::kUndefined;
+    tint::builtin::AddressSpace address_space = tint::builtin::AddressSpace::kUndefined;
 };
 
 /// Inequality operator for AccessRoot
@@ -450,7 +450,7 @@
                 Switch(
                     variable->Declaration(),
                     [&](const ast::Var*) {
-                        if (variable->AddressSpace() != type::AddressSpace::kHandle) {
+                        if (variable->AddressSpace() != builtin::AddressSpace::kHandle) {
                             // Start a new access chain for the non-handle 'var' access
                             create_new_chain();
                         }
@@ -749,15 +749,15 @@
 
     /// @returns true if the address space @p address_space requires transforming given the
     /// transform's options.
-    bool AddressSpaceRequiresTransform(type::AddressSpace address_space) const {
+    bool AddressSpaceRequiresTransform(builtin::AddressSpace address_space) const {
         switch (address_space) {
-            case type::AddressSpace::kUniform:
-            case type::AddressSpace::kStorage:
-            case type::AddressSpace::kWorkgroup:
+            case builtin::AddressSpace::kUniform:
+            case builtin::AddressSpace::kStorage:
+            case builtin::AddressSpace::kWorkgroup:
                 return true;
-            case type::AddressSpace::kPrivate:
+            case builtin::AddressSpace::kPrivate:
                 return opts.transform_private;
-            case type::AddressSpace::kFunction:
+            case builtin::AddressSpace::kFunction:
                 return opts.transform_function;
             default:
                 return false;
@@ -1180,9 +1180,9 @@
         for (auto* param : fn->Parameters()) {
             if (auto* ptr = param->Type()->As<type::Pointer>()) {
                 switch (ptr->AddressSpace()) {
-                    case type::AddressSpace::kUniform:
-                    case type::AddressSpace::kStorage:
-                    case type::AddressSpace::kWorkgroup:
+                    case builtin::AddressSpace::kUniform:
+                    case builtin::AddressSpace::kStorage:
+                    case builtin::AddressSpace::kWorkgroup:
                         return true;
                     default:
                         return false;
@@ -1193,8 +1193,8 @@
     }
 
     /// @returns true if the given address space is 'private' or 'function'.
-    static bool IsPrivateOrFunction(const type::AddressSpace sc) {
-        return sc == type::AddressSpace::kPrivate || sc == type::AddressSpace::kFunction;
+    static bool IsPrivateOrFunction(const builtin::AddressSpace sc) {
+        return sc == builtin::AddressSpace::kPrivate || sc == builtin::AddressSpace::kFunction;
     }
 };
 
diff --git a/src/tint/transform/direct_variable_access_test.cc b/src/tint/transform/direct_variable_access_test.cc
index 71e7c94..f017662 100644
--- a/src/tint/transform/direct_variable_access_test.cc
+++ b/src/tint/transform/direct_variable_access_test.cc
@@ -818,7 +818,7 @@
   mat : mat3x4<f32>,
 };
 
-type InnerArr = array<Inner, 4>;
+alias InnerArr = array<Inner, 4>;
 
 struct Outer {
   arr : InnerArr,
@@ -1112,7 +1112,7 @@
   mat : mat3x4<f32>,
 };
 
-type InnerArr = array<Inner, 4>;
+alias InnerArr = array<Inner, 4>;
 
 struct Outer {
   arr : InnerArr,
@@ -1356,7 +1356,7 @@
   mat : mat3x4<f32>,
 };
 
-type InnerArr = array<Inner, 4>;
+alias InnerArr = array<Inner, 4>;
 
 struct Outer {
   arr : InnerArr,
@@ -1828,7 +1828,7 @@
   mat : mat3x4<f32>,
 };
 
-type InnerArr = array<Inner, 4>;
+alias InnerArr = array<Inner, 4>;
 
 struct Outer {
   arr : InnerArr,
diff --git a/src/tint/transform/first_index_offset.cc b/src/tint/transform/first_index_offset.cc
index e739fae..59588e2 100644
--- a/src/tint/transform/first_index_offset.cc
+++ b/src/tint/transform/first_index_offset.cc
@@ -18,6 +18,7 @@
 #include <unordered_map>
 #include <utility>
 
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/member_accessor_expression.h"
@@ -88,7 +89,7 @@
         if (auto* var = node->As<ast::Variable>()) {
             for (auto* attr : var->attributes) {
                 if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
-                    builtin::BuiltinValue builtin = builtin_attr->builtin;
+                    builtin::BuiltinValue builtin = src->Sem().Get(builtin_attr)->Value();
                     if (builtin == builtin::BuiltinValue::kVertexIndex) {
                         auto* sem_var = ctx.src->Sem().Get(var);
                         builtin_vars.emplace(sem_var, kFirstVertexName);
@@ -105,7 +106,7 @@
         if (auto* member = node->As<ast::StructMember>()) {
             for (auto* attr : member->attributes) {
                 if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
-                    builtin::BuiltinValue builtin = builtin_attr->builtin;
+                    builtin::BuiltinValue builtin = src->Sem().Get(builtin_attr)->Value();
                     if (builtin == builtin::BuiltinValue::kVertexIndex) {
                         auto* sem_mem = ctx.src->Sem().Get(member);
                         builtin_members.emplace(sem_mem, kFirstVertexName);
@@ -130,7 +131,7 @@
 
         // Create a global to hold the uniform buffer
         Symbol buffer_name = b.Sym();
-        b.GlobalVar(buffer_name, b.ty.Of(struct_), type::AddressSpace::kUniform,
+        b.GlobalVar(buffer_name, b.ty.Of(struct_), builtin::AddressSpace::kUniform,
                     utils::Vector{
                         b.Binding(AInt(ub_binding)),
                         b.Group(AInt(ub_group)),
diff --git a/src/tint/transform/localize_struct_array_assignment.cc b/src/tint/transform/localize_struct_array_assignment.cc
index 5f70731..f5f8744 100644
--- a/src/tint/transform/localize_struct_array_assignment.cc
+++ b/src/tint/transform/localize_struct_array_assignment.cc
@@ -60,8 +60,9 @@
                     continue;
                 }
                 auto og = GetOriginatingTypeAndAddressSpace(assign_stmt);
-                if (!(og.first->Is<sem::Struct>() && (og.second == type::AddressSpace::kFunction ||
-                                                      og.second == type::AddressSpace::kPrivate))) {
+                if (!(og.first->Is<sem::Struct>() &&
+                      (og.second == builtin::AddressSpace::kFunction ||
+                       og.second == builtin::AddressSpace::kPrivate))) {
                     continue;
                 }
 
@@ -184,7 +185,7 @@
     // Returns the type and address space of the originating variable of the lhs
     // of the assignment statement.
     // See https://www.w3.org/TR/WGSL/#originating-variable-section
-    std::pair<const type::Type*, type::AddressSpace> GetOriginatingTypeAndAddressSpace(
+    std::pair<const type::Type*, builtin::AddressSpace> GetOriginatingTypeAndAddressSpace(
         const ast::AssignmentStatement* assign_stmt) {
         auto* root_ident = src->Sem().GetVal(assign_stmt->lhs)->RootIdentifier();
         if (TINT_UNLIKELY(!root_ident)) {
@@ -206,7 +207,7 @@
                 TINT_ICE(Transform, b.Diagnostics())
                     << "Expecting to find variable of type pointer or reference on lhs "
                        "of assignment statement";
-                return std::pair<const type::Type*, type::AddressSpace>{};
+                return std::pair<const type::Type*, builtin::AddressSpace>{};
             });
     }
 };
diff --git a/src/tint/transform/module_scope_var_to_entry_point_param.cc b/src/tint/transform/module_scope_var_to_entry_point_param.cc
index 364087b..044133c 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/transform/module_scope_var_to_entry_point_param.cc
@@ -117,15 +117,14 @@
                                      WorkgroupParameterMemberList& workgroup_parameter_members,
                                      bool& is_pointer,
                                      bool& is_wrapped) {
-        auto* var_ast = var->Declaration()->As<ast::Var>();
         auto* ty = var->Type()->UnwrapRef();
 
         // Helper to create an AST node for the store type of the variable.
         auto store_type = [&]() { return CreateASTTypeFor(ctx, ty); };
 
-        type::AddressSpace sc = var->AddressSpace();
+        builtin::AddressSpace sc = var->AddressSpace();
         switch (sc) {
-            case type::AddressSpace::kHandle: {
+            case builtin::AddressSpace::kHandle: {
                 // For a texture or sampler variable, redeclare it as an entry point parameter.
                 // Disable entry point parameter validation.
                 auto* disable_validation =
@@ -137,8 +136,8 @@
 
                 break;
             }
-            case type::AddressSpace::kStorage:
-            case type::AddressSpace::kUniform: {
+            case builtin::AddressSpace::kStorage:
+            case builtin::AddressSpace::kUniform: {
                 // Variables into the Storage and Uniform address spaces are redeclared as entry
                 // point parameters with a pointer type.
                 auto attributes = ctx.Clone(var->Declaration()->attributes);
@@ -160,14 +159,16 @@
                     is_wrapped = true;
                 }
 
-                param_type = ctx.dst->ty.pointer(param_type, sc, var_ast->declared_access);
+                param_type = sc == builtin::AddressSpace::kStorage
+                                 ? ctx.dst->ty.pointer(param_type, sc, var->Access())
+                                 : ctx.dst->ty.pointer(param_type, sc);
                 auto* param = ctx.dst->Param(new_var_symbol, param_type, attributes);
                 ctx.InsertFront(func->params, param);
                 is_pointer = true;
 
                 break;
             }
-            case type::AddressSpace::kWorkgroup: {
+            case builtin::AddressSpace::kWorkgroup: {
                 if (ContainsMatrix(var->Type())) {
                     // Due to a bug in the MSL compiler, we use a threadgroup memory argument for
                     // any workgroup allocation that contains a matrix. See crbug.com/tint/938.
@@ -183,7 +184,7 @@
                         ctx.dst->MemberAccessor(ctx.dst->Deref(workgroup_param()), member));
                     auto* local_var = ctx.dst->Let(
                         new_var_symbol,
-                        ctx.dst->ty.pointer(store_type(), type::AddressSpace::kWorkgroup),
+                        ctx.dst->ty.pointer(store_type(), builtin::AddressSpace::kWorkgroup),
                         member_ptr);
                     ctx.InsertFront(func->body->statements, ctx.dst->Decl(local_var));
                     is_pointer = true;
@@ -192,7 +193,7 @@
                 }
                 [[fallthrough]];
             }
-            case type::AddressSpace::kPrivate: {
+            case builtin::AddressSpace::kPrivate: {
                 // Variables in the Private and Workgroup address spaces are redeclared at function
                 // scope. Disable address space validation on this variable.
                 auto* disable_validation =
@@ -204,7 +205,7 @@
 
                 break;
             }
-            case type::AddressSpace::kPushConstant: {
+            case builtin::AddressSpace::kPushConstant: {
                 ctx.dst->Diagnostics().add_error(
                     diag::System::Transform,
                     "unhandled module-scope address space (" + utils::ToString(sc) + ")");
@@ -228,18 +229,17 @@
                                        const sem::Variable* var,
                                        Symbol new_var_symbol,
                                        bool& is_pointer) {
-        auto* var_ast = var->Declaration()->As<ast::Var>();
         auto* ty = var->Type()->UnwrapRef();
         auto param_type = CreateASTTypeFor(ctx, ty);
         auto sc = var->AddressSpace();
         switch (sc) {
-            case type::AddressSpace::kPrivate:
-            case type::AddressSpace::kStorage:
-            case type::AddressSpace::kUniform:
-            case type::AddressSpace::kHandle:
-            case type::AddressSpace::kWorkgroup:
+            case builtin::AddressSpace::kPrivate:
+            case builtin::AddressSpace::kStorage:
+            case builtin::AddressSpace::kUniform:
+            case builtin::AddressSpace::kHandle:
+            case builtin::AddressSpace::kWorkgroup:
                 break;
-            case type::AddressSpace::kPushConstant: {
+            case builtin::AddressSpace::kPushConstant: {
                 ctx.dst->Diagnostics().add_error(
                     diag::System::Transform,
                     "unhandled module-scope address space (" + utils::ToString(sc) + ")");
@@ -254,7 +254,9 @@
         // Use a pointer for non-handle types.
         utils::Vector<const ast::Attribute*, 2> attributes;
         if (!ty->is_handle()) {
-            param_type = ctx.dst->ty.pointer(param_type, sc, var_ast->declared_access);
+            param_type = sc == builtin::AddressSpace::kStorage
+                             ? ctx.dst->ty.pointer(param_type, sc, var->Access())
+                             : ctx.dst->ty.pointer(param_type, sc);
             is_pointer = true;
 
             // Disable validation of the parameter's address space and of arguments passed to it.
@@ -321,7 +323,7 @@
 
             bool needs_processing = false;
             for (auto* var : func_sem->TransitivelyReferencedGlobals()) {
-                if (var->AddressSpace() != type::AddressSpace::kNone) {
+                if (var->AddressSpace() != builtin::AddressSpace::kUndefined) {
                     needs_processing = true;
                     break;
                 }
@@ -378,7 +380,7 @@
 
             // Process and redeclare all variables referenced by the function.
             for (auto* var : func_sem->TransitivelyReferencedGlobals()) {
-                if (var->AddressSpace() == type::AddressSpace::kNone) {
+                if (var->AddressSpace() == builtin::AddressSpace::kUndefined) {
                     continue;
                 }
                 if (local_private_vars_.count(var)) {
@@ -396,7 +398,7 @@
 
                 // Check if this is a private variable that is only referenced by this function.
                 bool local_private = false;
-                if (var->AddressSpace() == type::AddressSpace::kPrivate) {
+                if (var->AddressSpace() == builtin::AddressSpace::kPrivate) {
                     local_private = true;
                     for (auto* user : var->Users()) {
                         auto* stmt = user->Stmt();
@@ -414,7 +416,7 @@
                     auto* initializer = ctx.Clone(var->Declaration()->initializer);
                     auto* local_var = ctx.dst->Var(new_var_symbol,
                                                    CreateASTTypeFor(ctx, var->Type()->UnwrapRef()),
-                                                   type::AddressSpace::kPrivate, initializer,
+                                                   builtin::AddressSpace::kPrivate, initializer,
                                                    utils::Vector{disable_validation});
                     ctx.InsertFront(func_ast->body->statements, ctx.dst->Decl(local_var));
                     local_private_vars_.insert(var);
@@ -426,7 +428,7 @@
                                                     is_wrapped);
                     } else {
                         ProcessVariableInUserFunction(func_ast, var, new_var_symbol, is_pointer);
-                        if (var->AddressSpace() == type::AddressSpace::kWorkgroup) {
+                        if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
                             needs_pointer_aliasing = true;
                         }
                     }
@@ -451,7 +453,7 @@
                 auto* str =
                     ctx.dst->Structure(ctx.dst->Sym(), std::move(workgroup_parameter_members));
                 auto param_type =
-                    ctx.dst->ty.pointer(ctx.dst->ty.Of(str), type::AddressSpace::kWorkgroup);
+                    ctx.dst->ty.pointer(ctx.dst->ty.Of(str), builtin::AddressSpace::kWorkgroup);
                 auto* param = ctx.dst->Param(
                     workgroup_param(), param_type,
                     utils::Vector{
@@ -470,7 +472,7 @@
                 // For entry points, pass non-handle types as pointers.
                 for (auto* target_var : target_sem->TransitivelyReferencedGlobals()) {
                     auto sc = target_var->AddressSpace();
-                    if (sc == type::AddressSpace::kNone) {
+                    if (sc == builtin::AddressSpace::kUndefined) {
                         continue;
                     }
 
@@ -501,7 +503,7 @@
         // Now remove all module-scope variables with these address spaces.
         for (auto* var_ast : ctx.src->AST().GlobalVariables()) {
             auto* var_sem = ctx.src->Sem().Get(var_ast);
-            if (var_sem->AddressSpace() != type::AddressSpace::kNone) {
+            if (var_sem->AddressSpace() != builtin::AddressSpace::kUndefined) {
                 ctx.Remove(ctx.src->AST().GlobalDeclarations(), var_ast);
             }
         }
diff --git a/src/tint/transform/module_scope_var_to_entry_point_param_test.cc b/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
index 999761d..a9aaa28 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
+++ b/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
@@ -435,7 +435,7 @@
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<storage, S>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<storage, S, read>) {
   _ = *(tint_symbol);
   _ = *(tint_symbol_1);
 }
@@ -465,7 +465,7 @@
 
     auto* expect = R"(
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<storage, S>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<storage, S, read>) {
   _ = *(tint_symbol);
   _ = *(tint_symbol_1);
 }
@@ -497,7 +497,7 @@
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1, read>) {
   _ = (*(tint_symbol)).arr[0];
 }
 )";
@@ -524,7 +524,7 @@
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1, read>) {
   _ = (*(tint_symbol)).arr[0];
 }
 )";
@@ -554,12 +554,12 @@
   arr : array<f32>,
 }
 
-fn foo(@internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<storage, array<f32>>) {
+fn foo(@internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<storage, array<f32>, read>) {
   _ = (*(tint_symbol))[0];
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<storage, tint_symbol_2>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<storage, tint_symbol_2, read>) {
   foo(&((*(tint_symbol_1)).arr));
 }
 )";
@@ -589,11 +589,11 @@
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<storage, tint_symbol_2>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<storage, tint_symbol_2, read>) {
   foo(&((*(tint_symbol_1)).arr));
 }
 
-fn foo(@internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<storage, array<f32>>) {
+fn foo(@internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<storage, array<f32>, read>) {
   _ = (*(tint_symbol))[0];
 }
 )";
@@ -605,7 +605,7 @@
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArray_Alias) {
     auto* src = R"(
-type myarray = array<f32>;
+alias myarray = array<f32>;
 
 @group(0) @binding(0)
 var<storage> buffer : myarray;
@@ -624,7 +624,7 @@
 alias myarray = array<f32>;
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1, read>) {
   _ = (*(tint_symbol)).arr[0];
 }
 )";
@@ -643,7 +643,7 @@
 
 @group(0) @binding(0) var<storage> buffer : myarray;
 
-type myarray = array<f32>;
+alias myarray = array<f32>;
 )";
 
     auto* expect = R"(
@@ -652,7 +652,7 @@
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1, read>) {
   _ = (*(tint_symbol)).arr[0];
 }
 
@@ -689,7 +689,7 @@
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1, read>) {
   _ = (*(tint_symbol)).arr[0];
 }
 )";
@@ -723,7 +723,7 @@
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol : ptr<storage, tint_symbol_1, read>) {
   _ = (*(tint_symbol)).arr[0];
 }
 )";
@@ -773,12 +773,12 @@
 fn no_uses() {
 }
 
-fn bar(a : f32, b : f32, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<uniform, S>, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<storage, S>) {
+fn bar(a : f32, b : f32, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<uniform, S>, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<storage, S, read>) {
   _ = *(tint_symbol);
   _ = *(tint_symbol_1);
 }
 
-fn foo(a : f32, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<uniform, S>, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<storage, S>) {
+fn foo(a : f32, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<uniform, S>, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<storage, S, read>) {
   let b : f32 = 2.0;
   _ = *(tint_symbol_2);
   bar(a, b, tint_symbol_2, tint_symbol_3);
@@ -786,7 +786,7 @@
 }
 
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_4 : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_5 : ptr<storage, S>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_4 : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_5 : ptr<storage, S, read>) {
   foo(1.0, tint_symbol_4, tint_symbol_5);
 }
 )";
@@ -830,11 +830,11 @@
 
     auto* expect = R"(
 @compute @workgroup_size(1)
-fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_4 : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_5 : ptr<storage, S>) {
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_4 : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_5 : ptr<storage, S, read>) {
   foo(1.0, tint_symbol_4, tint_symbol_5);
 }
 
-fn foo(a : f32, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<uniform, S>, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<storage, S>) {
+fn foo(a : f32, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<uniform, S>, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<storage, S, read>) {
   let b : f32 = 2.0;
   _ = *(tint_symbol_2);
   bar(a, b, tint_symbol_2, tint_symbol_3);
@@ -844,7 +844,7 @@
 fn no_uses() {
 }
 
-fn bar(a : f32, b : f32, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<uniform, S>, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<storage, S>) {
+fn bar(a : f32, b : f32, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol : ptr<uniform, S>, @internal(disable_validation__ignore_address_space) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<storage, S, read>) {
   _ = *(tint_symbol);
   _ = *(tint_symbol_1);
 }
diff --git a/src/tint/transform/multiplanar_external_texture.cc b/src/tint/transform/multiplanar_external_texture.cc
index 06dfba4..27eeeb0 100644
--- a/src/tint/transform/multiplanar_external_texture.cc
+++ b/src/tint/transform/multiplanar_external_texture.cc
@@ -144,7 +144,7 @@
             b.GlobalVar(syms.plane_1, b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32()),
                         b.Group(AInt(bps.plane_1.group)), b.Binding(AInt(bps.plane_1.binding)));
             syms.params = b.Symbols().New("ext_tex_params");
-            b.GlobalVar(syms.params, b.ty("ExternalTextureParams"), type::AddressSpace::kUniform,
+            b.GlobalVar(syms.params, b.ty("ExternalTextureParams"), builtin::AddressSpace::kUniform,
                         b.Group(AInt(bps.params.group)), b.Binding(AInt(bps.params.binding)));
 
             // Replace the original texture_external binding with a texture_2d<f32> binding.
@@ -351,8 +351,10 @@
                 single_plane_call = b.Call("textureLoad", "plane0", "coord", 0_a);
                 // textureLoad(plane0, coord, 0);
                 plane_0_call = b.Call("textureLoad", "plane0", "coord", 0_a);
-                // textureLoad(plane1, coord, 0);
-                plane_1_call = b.Call("textureLoad", "plane1", "coord", 0_a);
+                // let coord1 = coord >> 1;
+                stmts.Push(b.Decl(b.Let("coord1", b.Shr("coord", b.vec2<u32>(1_a)))));
+                // textureLoad(plane1, coord1, 0);
+                plane_1_call = b.Call("textureLoad", "plane1", "coord1", 0_a);
                 break;
             default:
                 TINT_ICE(Transform, b.Diagnostics()) << "unhandled builtin: " << call_type;
diff --git a/src/tint/transform/multiplanar_external_texture_test.cc b/src/tint/transform/multiplanar_external_texture_test.cc
index af1d0b4..916d56b 100644
--- a/src/tint/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/transform/multiplanar_external_texture_test.cc
@@ -32,7 +32,7 @@
 
 TEST_F(MultiplanarExternalTextureTest, ShouldRunHasExternalTextureAlias) {
     auto* src = R"(
-type ET = texture_external;
+alias ET = texture_external;
 )";
 
     DataMap data;
@@ -435,11 +435,12 @@
 }
 
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  let coord1 = (coord >> vec2<u32>(1));
   var color : vec3<f32>;
   if ((params.numPlanes == 1)) {
     color = textureLoad(plane0, coord, 0).rgb;
   } else {
-    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1) * params.yuvToRgbConversionMatrix);
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord1, 0).rg, 1) * params.yuvToRgbConversionMatrix);
   }
   if ((params.doYuvToRgbConversionOnly == 0)) {
     color = gammaCorrection(color, params.gammaDecodeParams);
@@ -450,11 +451,12 @@
 }
 
 fn textureLoadExternal_1(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<u32>, params : ExternalTextureParams) -> vec4<f32> {
+  let coord1 = (coord >> vec2<u32>(1));
   var color : vec3<f32>;
   if ((params.numPlanes == 1)) {
     color = textureLoad(plane0, coord, 0).rgb;
   } else {
-    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1) * params.yuvToRgbConversionMatrix);
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord1, 0).rg, 1) * params.yuvToRgbConversionMatrix);
   }
   if ((params.doYuvToRgbConversionOnly == 0)) {
     color = gammaCorrection(color, params.gammaDecodeParams);
@@ -526,11 +528,12 @@
 }
 
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  let coord1 = (coord >> vec2<u32>(1));
   var color : vec3<f32>;
   if ((params.numPlanes == 1)) {
     color = textureLoad(plane0, coord, 0).rgb;
   } else {
-    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1) * params.yuvToRgbConversionMatrix);
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord1, 0).rg, 1) * params.yuvToRgbConversionMatrix);
   }
   if ((params.doYuvToRgbConversionOnly == 0)) {
     color = gammaCorrection(color, params.gammaDecodeParams);
@@ -541,11 +544,12 @@
 }
 
 fn textureLoadExternal_1(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<u32>, params : ExternalTextureParams) -> vec4<f32> {
+  let coord1 = (coord >> vec2<u32>(1));
   var color : vec3<f32>;
   if ((params.numPlanes == 1)) {
     color = textureLoad(plane0, coord, 0).rgb;
   } else {
-    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1) * params.yuvToRgbConversionMatrix);
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord1, 0).rg, 1) * params.yuvToRgbConversionMatrix);
   }
   if ((params.doYuvToRgbConversionOnly == 0)) {
     color = gammaCorrection(color, params.gammaDecodeParams);
@@ -644,11 +648,12 @@
 }
 
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  let coord1 = (coord >> vec2<u32>(1));
   var color : vec3<f32>;
   if ((params.numPlanes == 1)) {
     color = textureLoad(plane0, coord, 0).rgb;
   } else {
-    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1) * params.yuvToRgbConversionMatrix);
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord1, 0).rg, 1) * params.yuvToRgbConversionMatrix);
   }
   if ((params.doYuvToRgbConversionOnly == 0)) {
     color = gammaCorrection(color, params.gammaDecodeParams);
@@ -739,11 +744,12 @@
 }
 
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  let coord1 = (coord >> vec2<u32>(1));
   var color : vec3<f32>;
   if ((params.numPlanes == 1)) {
     color = textureLoad(plane0, coord, 0).rgb;
   } else {
-    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1) * params.yuvToRgbConversionMatrix);
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord1, 0).rg, 1) * params.yuvToRgbConversionMatrix);
   }
   if ((params.doYuvToRgbConversionOnly == 0)) {
     color = gammaCorrection(color, params.gammaDecodeParams);
@@ -887,7 +893,7 @@
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParam) {
     auto* src = R"(
 fn f(t : texture_external, s : sampler) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
 }
 
 @group(0) @binding(0) var ext_tex : texture_external;
@@ -955,7 +961,7 @@
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
-  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+  _ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
 }
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
@@ -985,7 +991,7 @@
 }
 
 fn f(t : texture_external, s : sampler) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
 }
 
 @group(0) @binding(0) var ext_tex : texture_external;
@@ -1053,7 +1059,7 @@
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
-  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+  _ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
 }
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
@@ -1073,7 +1079,7 @@
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsSecondParam) {
     auto* src = R"(
 fn f(s : sampler, t : texture_external) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
 }
 
 @group(0) @binding(0) var ext_tex : texture_external;
@@ -1141,7 +1147,7 @@
 }
 
 fn f(s : sampler, t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams) {
-  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+  _ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
 }
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
@@ -1166,8 +1172,8 @@
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamMultiple) {
     auto* src = R"(
 fn f(t : texture_external, s : sampler, t2 : texture_external) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
-  textureSampleBaseClampToEdge(t2, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t2, s, vec2<f32>(1.0, 2.0));
 }
 
 @group(0) @binding(0) var ext_tex : texture_external;
@@ -1240,8 +1246,8 @@
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
-  textureSampleExternal(t, ext_tex_plane_1_2, s, vec2<f32>(1.0, 2.0), ext_tex_params_2);
-  textureSampleExternal(t2, ext_tex_plane_1_3, s, vec2<f32>(1.0, 2.0), ext_tex_params_3);
+  _ = textureSampleExternal(t, ext_tex_plane_1_2, s, vec2<f32>(1.0, 2.0), ext_tex_params_2);
+  _ = textureSampleExternal(t2, ext_tex_plane_1_3, s, vec2<f32>(1.0, 2.0), ext_tex_params_3);
 }
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
@@ -1274,8 +1280,8 @@
 }
 
 fn f(t : texture_external, s : sampler, t2 : texture_external) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
-  textureSampleBaseClampToEdge(t2, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t2, s, vec2<f32>(1.0, 2.0));
 }
 
 @group(0) @binding(0) var ext_tex : texture_external;
@@ -1349,8 +1355,8 @@
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
-  textureSampleExternal(t, ext_tex_plane_1_2, s, vec2<f32>(1.0, 2.0), ext_tex_params_2);
-  textureSampleExternal(t2, ext_tex_plane_1_3, s, vec2<f32>(1.0, 2.0), ext_tex_params_3);
+  _ = textureSampleExternal(t, ext_tex_plane_1_2, s, vec2<f32>(1.0, 2.0), ext_tex_params_2);
+  _ = textureSampleExternal(t2, ext_tex_plane_1_3, s, vec2<f32>(1.0, 2.0), ext_tex_params_3);
 }
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
@@ -1373,7 +1379,7 @@
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamNested) {
     auto* src = R"(
 fn nested(t : texture_external, s : sampler) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
 }
 
 fn f(t : texture_external, s : sampler) {
@@ -1445,7 +1451,7 @@
 }
 
 fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
-  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+  _ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler) {
@@ -1474,7 +1480,7 @@
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamNested_OutOfOrder) {
     auto* src = R"(
 fn nested(t : texture_external, s : sampler) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
 }
 
 fn f(t : texture_external, s : sampler) {
@@ -1546,7 +1552,7 @@
 }
 
 fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
-  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+  _ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler) {
@@ -1616,10 +1622,10 @@
 // Tests that the the transform handles aliases to external textures
 TEST_F(MultiplanarExternalTextureTest, ExternalTextureAlias) {
     auto* src = R"(
-type ET = texture_external;
+alias ET = texture_external;
 
 fn f(t : ET, s : sampler) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
 }
 
 @group(0) @binding(0) var ext_tex : ET;
@@ -1689,7 +1695,7 @@
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
-  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+  _ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
 }
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
@@ -1718,13 +1724,13 @@
 }
 
 fn f(t : ET, s : sampler) {
-  textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
+  _ = textureSampleBaseClampToEdge(t, s, vec2<f32>(1.0, 2.0));
 }
 
 @group(0) @binding(0) var ext_tex : ET;
 @group(0) @binding(1) var smp : sampler;
 
-type ET = texture_external;
+alias ET = texture_external;
 )";
 
     auto* expect = R"(
@@ -1788,7 +1794,7 @@
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
-  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+  _ = textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
 }
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
diff --git a/src/tint/transform/num_workgroups_from_uniform.cc b/src/tint/transform/num_workgroups_from_uniform.cc
index 35e59fb..e4bb05e 100644
--- a/src/tint/transform/num_workgroups_from_uniform.cc
+++ b/src/tint/transform/num_workgroups_from_uniform.cc
@@ -19,6 +19,7 @@
 #include <unordered_set>
 #include <utility>
 
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/transform/canonicalize_entry_point_io.h"
@@ -33,7 +34,7 @@
 bool ShouldRun(const Program* program) {
     for (auto* node : program->ASTNodes().Objects()) {
         if (auto* attr = node->As<ast::BuiltinAttribute>()) {
-            if (attr->builtin == builtin::BuiltinValue::kNumWorkgroups) {
+            if (program->Sem().Get(attr)->Value() == builtin::BuiltinValue::kNumWorkgroups) {
                 return true;
             }
         }
@@ -100,7 +101,8 @@
             for (auto* member : str->Members()) {
                 auto* builtin =
                     ast::GetAttribute<ast::BuiltinAttribute>(member->Declaration()->attributes);
-                if (!builtin || builtin->builtin != builtin::BuiltinValue::kNumWorkgroups) {
+                if (!builtin ||
+                    src->Sem().Get(builtin)->Value() != builtin::BuiltinValue::kNumWorkgroups) {
                     continue;
                 }
 
@@ -158,9 +160,9 @@
                 binding = 0;
             }
 
-            num_workgroups_ubo =
-                b.GlobalVar(b.Sym(), b.ty.Of(num_workgroups_struct), type::AddressSpace::kUniform,
-                            b.Group(AInt(group)), b.Binding(AInt(binding)));
+            num_workgroups_ubo = b.GlobalVar(b.Sym(), b.ty.Of(num_workgroups_struct),
+                                             builtin::AddressSpace::kUniform, b.Group(AInt(group)),
+                                             b.Binding(AInt(binding)));
         }
         return num_workgroups_ubo;
     };
diff --git a/src/tint/transform/pad_structs.cc b/src/tint/transform/pad_structs.cc
index 954069c..8516aa3 100644
--- a/src/tint/transform/pad_structs.cc
+++ b/src/tint/transform/pad_structs.cc
@@ -18,11 +18,12 @@
 #include <unordered_map>
 #include <utility>
 
+#include "src/tint/ast/disable_validation_attribute.h"
 #include "src/tint/ast/parameter.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/module.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -36,7 +37,10 @@
                    utils::Hashset<const ast::StructMember*, 8>* padding_members,
                    ProgramBuilder* b,
                    uint32_t bytes) {
-    for (uint32_t i = 0; i < bytes / 4u; ++i) {
+    const size_t count = bytes / 4u;
+    padding_members->Reserve(count);
+    new_members->Reserve(count);
+    for (uint32_t i = 0; i < count; ++i) {
         auto name = b->Symbols().New("pad");
         auto* member = b->Member(name, b->ty.u32());
         padding_members->Add(member);
@@ -80,7 +84,7 @@
             new_members.Push(b.Member(name, type));
 
             uint32_t size = ty->Size();
-            if (ty->Is<sem::Struct>() && str->UsedAs(type::AddressSpace::kUniform)) {
+            if (ty->Is<sem::Struct>() && str->UsedAs(builtin::AddressSpace::kUniform)) {
                 // std140 structs should be padded out to 16 bytes.
                 size = utils::RoundUp(16u, size);
             } else if (auto* array_ty = ty->As<type::Array>()) {
@@ -93,14 +97,21 @@
 
         // Add any required padding after the last member, if it's not a runtime-sized array.
         uint32_t struct_size = str->Size();
-        if (str->UsedAs(type::AddressSpace::kUniform)) {
+        if (str->UsedAs(builtin::AddressSpace::kUniform)) {
             struct_size = utils::RoundUp(16u, struct_size);
         }
         if (offset < struct_size && !has_runtime_sized_array) {
             CreatePadding(&new_members, &padding_members, ctx.dst, struct_size - offset);
         }
-        auto* new_struct =
-            b.create<ast::Struct>(ctx.Clone(ast_str->name), std::move(new_members), utils::Empty);
+
+        utils::Vector<const ast::Attribute*, 1> struct_attribs;
+        if (!padding_members.IsEmpty()) {
+            struct_attribs =
+                utils::Vector{b.Disable(ast::DisabledValidation::kIgnoreStructMemberLimit)};
+        }
+
+        auto* new_struct = b.create<ast::Struct>(ctx.Clone(ast_str->name), std::move(new_members),
+                                                 std::move(struct_attribs));
         replaced_structs[ast_str] = new_struct;
         return new_struct;
     });
@@ -114,7 +125,7 @@
         if (!call) {
             return nullptr;
         }
-        auto* cons = call->Target()->As<sem::TypeInitializer>();
+        auto* cons = call->Target()->As<sem::ValueConstructor>();
         if (!cons) {
             return nullptr;
         }
diff --git a/src/tint/transform/pad_structs_test.cc b/src/tint/transform/pad_structs_test.cc
index 6b1a70f..0826467 100644
--- a/src/tint/transform/pad_structs_test.cc
+++ b/src/tint/transform/pad_structs_test.cc
@@ -47,6 +47,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   x : i32,
   pad : u32,
@@ -81,6 +82,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   x : i32,
   pad : u32,
@@ -118,6 +120,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   x : i32,
   pad : u32,
@@ -158,6 +161,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   x : i32,
   pad : u32,
@@ -198,6 +202,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   x : i32,
   pad : u32,
@@ -273,6 +278,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   a : i32,
   pad : u32,
@@ -320,6 +326,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   a : i32,
   pad : u32,
@@ -367,6 +374,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   a : i32,
   pad : u32,
@@ -501,6 +509,7 @@
   b : i32,
 }
 
+@internal(disable_validation__ignore_struct_member)
 struct S {
   a : vec4<f32>,
   b : array<T, 1u>,
@@ -537,6 +546,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   a : f32,
   pad : u32,
@@ -573,6 +583,7 @@
 }
 )";
     auto* expect = R"(
+@internal(disable_validation__ignore_struct_member)
 struct S {
   a : f32,
   pad : u32,
diff --git a/src/tint/transform/preserve_padding.cc b/src/tint/transform/preserve_padding.cc
index ba30933..cb5a8ee 100644
--- a/src/tint/transform/preserve_padding.cc
+++ b/src/tint/transform/preserve_padding.cc
@@ -53,7 +53,8 @@
                         // Ignore phony assignment.
                         return;
                     }
-                    if (ty->As<type::Reference>()->AddressSpace() != type::AddressSpace::kStorage) {
+                    if (ty->As<type::Reference>()->AddressSpace() !=
+                        builtin::AddressSpace::kStorage) {
                         // We only care about assignments that write to variables in the storage
                         // address space, as nothing else is host-visible.
                         return;
@@ -120,8 +121,8 @@
                 auto helper_name = b.Symbols().New("assign_and_preserve_padding");
                 utils::Vector<const ast::Parameter*, 2> params = {
                     b.Param(kDestParamName,
-                            b.ty.pointer(CreateASTTypeFor(ctx, ty), type::AddressSpace::kStorage,
-                                         type::Access::kReadWrite)),
+                            b.ty.pointer(CreateASTTypeFor(ctx, ty), builtin::AddressSpace::kStorage,
+                                         builtin::Access::kReadWrite)),
                     b.Param(kValueParamName, CreateASTTypeFor(ctx, ty)),
                 };
                 b.Func(helper_name, params, b.ty.void_(), body());
diff --git a/src/tint/transform/preserve_padding_test.cc b/src/tint/transform/preserve_padding_test.cc
index 854b4a5..9405210 100644
--- a/src/tint/transform/preserve_padding_test.cc
+++ b/src/tint/transform/preserve_padding_test.cc
@@ -373,7 +373,7 @@
 
 TEST_F(PreservePaddingTest, ArrayOfArray) {
     auto* src = R"(
-type Array = array<array<vec3<u32>, 4>, 3>;
+alias Array = array<array<vec3<u32>, 4>, 3>;
 
 @group(0) @binding(0) var<storage, read_write> v : Array;
 
diff --git a/src/tint/transform/promote_initializers_to_let.cc b/src/tint/transform/promote_initializers_to_let.cc
index 20f7d32..e201f11 100644
--- a/src/tint/transform/promote_initializers_to_let.cc
+++ b/src/tint/transform/promote_initializers_to_let.cc
@@ -20,7 +20,7 @@
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/statement.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
 #include "src/tint/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/type/struct.h"
 #include "src/tint/utils/hashset.h"
@@ -58,8 +58,8 @@
             }
 
             auto* ctor = root_expr->UnwrapMaterialize()->As<sem::Call>();
-            if (!ctor || !ctor->Target()->Is<sem::TypeInitializer>()) {
-                // Root expression is not a type constructor. Not interested in this.
+            if (!ctor || !ctor->Target()->Is<sem::ValueConstructor>()) {
+                // Root expression is not a value constructor. Not interested in this.
                 return false;
             }
         }
@@ -134,7 +134,7 @@
         return expr_a->Declaration()->node_id < expr_b->Declaration()->node_id;
     });
 
-    // Hoist all the expression in to_hoist  to a constant variable, declared just before the
+    // Hoist all the expressions in to_hoist to a constant variable, declared just before the
     // statement of usage.
     HoistToDeclBefore hoist_to_decl_before(ctx);
     for (auto* expr : to_hoist) {
diff --git a/src/tint/transform/promote_initializers_to_let_test.cc b/src/tint/transform/promote_initializers_to_let_test.cc
index 32e2ec9..1198067 100644
--- a/src/tint/transform/promote_initializers_to_let_test.cc
+++ b/src/tint/transform/promote_initializers_to_let_test.cc
@@ -61,7 +61,7 @@
   var f1 = 2.0;
   var f2 = 3.0;
   var f3 = 4.0;
-  let tint_symbol = array<f32, 4u>(f0, f1, f2, f3);
+  let tint_symbol : array<f32, 4u> = array<f32, 4u>(f0, f1, f2, f3);
   var i = tint_symbol[2];
 }
 )";
@@ -110,7 +110,7 @@
 
 fn f() {
   let runtime_value = 1;
-  let tint_symbol = S(runtime_value, 2.0, vec3<f32>());
+  let tint_symbol : S = S(runtime_value, 2.0, vec3<f32>());
   var x = tint_symbol.b;
 }
 )";
@@ -137,7 +137,7 @@
     auto* expect = R"(
 fn f() {
   let runtime_value = 1;
-  let tint_symbol = S(runtime_value, 2.0, vec3<f32>());
+  let tint_symbol : S = S(runtime_value, 2.0, vec3<f32>());
   var x = tint_symbol.b;
 }
 
@@ -209,7 +209,7 @@
 
 @vertex
 fn vs_main(@builtin(vertex_index) in_vertex_index : u32) -> @builtin(position) vec4<f32> {
-  let tint_symbol = TRI_VERTICES;
+  let tint_symbol : array<vec4<f32>, 3u> = TRI_VERTICES;
   return tint_symbol[in_vertex_index];
 }
 )";
@@ -249,7 +249,7 @@
   const f1 = 2.0;
   const C = array<f32, 2u>(f0, f1);
   let runtime_value = 1;
-  let tint_symbol = C;
+  let tint_symbol : array<f32, 2u> = C;
   var i = tint_symbol[runtime_value];
 }
 )";
@@ -272,7 +272,7 @@
     auto* expect = R"(
 fn f() {
   var insert_after = 1;
-  let tint_symbol = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+  let tint_symbol : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
   for(var i = tint_symbol[insert_after]; ; ) {
     break;
   }
@@ -301,7 +301,7 @@
   const arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
   let runtime_value = 1;
   var insert_after = 1;
-  let tint_symbol = arr;
+  let tint_symbol : array<f32, 4u> = arr;
   for(var i = tint_symbol[runtime_value]; ; ) {
     break;
   }
@@ -332,7 +332,7 @@
 fn f() {
   let runtime_value = 1;
   var insert_after = 1;
-  let tint_symbol = arr;
+  let tint_symbol : array<f32, 4u> = arr;
   for(var i = tint_symbol[runtime_value]; ; ) {
     break;
   }
@@ -377,7 +377,7 @@
 
 fn f() {
   var insert_after = 1;
-  let tint_symbol = S(1, 2.0, vec3<f32>());
+  let tint_symbol : S = S(1, 2.0, vec3<f32>());
   for(var x = get_b_runtime(tint_symbol); ; ) {
     break;
   }
@@ -412,7 +412,7 @@
     auto* expect = R"(
 fn f() {
   var insert_after = 1;
-  let tint_symbol = S(1, 2.0, vec3<f32>());
+  let tint_symbol : S = S(1, 2.0, vec3<f32>());
   for(var x = get_b_runtime(tint_symbol); ; ) {
     break;
   }
@@ -448,7 +448,7 @@
 fn f() {
   var f = 1.0;
   loop {
-    let tint_symbol = array<f32, 1u>(f);
+    let tint_symbol : array<f32, 1u> = array<f32, 1u>(f);
     if (!((f == tint_symbol[0]))) {
       break;
     }
@@ -488,7 +488,7 @@
   {
     var i = f;
     loop {
-      let tint_symbol = arr;
+      let tint_symbol : array<f32, 1u> = arr;
       if (!((i == tint_symbol[runtime_value]))) {
         break;
       }
@@ -533,7 +533,7 @@
   {
     var i = f;
     loop {
-      let tint_symbol = arr;
+      let tint_symbol : array<f32, 1u> = arr;
       if (!((i == tint_symbol[runtime_value]))) {
         break;
       }
@@ -578,7 +578,7 @@
     }
 
     continuing {
-      let tint_symbol = array<f32, 1u>(1.0);
+      let tint_symbol : array<f32, 1u> = array<f32, 1u>(1.0);
       f = (f + tint_symbol[runtime_value]);
     }
   }
@@ -616,7 +616,7 @@
     }
 
     continuing {
-      let tint_symbol = arr;
+      let tint_symbol : array<f32, 1u> = arr;
       f = (f + tint_symbol[runtime_value]);
     }
   }
@@ -656,7 +656,7 @@
     }
 
     continuing {
-      let tint_symbol = arr;
+      let tint_symbol : array<f32, 1u> = arr;
       f = (f + tint_symbol[runtime_value]);
     }
   }
@@ -683,11 +683,11 @@
     auto* expect = R"(
 fn f() {
   let runtime_value = 0;
-  let tint_symbol = array<f32, 1u>(0.0);
+  let tint_symbol : array<f32, 1u> = array<f32, 1u>(0.0);
   {
     var f = tint_symbol[runtime_value];
     loop {
-      let tint_symbol_1 = array<f32, 1u>(1.0);
+      let tint_symbol_1 : array<f32, 1u> = array<f32, 1u>(1.0);
       if (!((f < tint_symbol_1[runtime_value]))) {
         break;
       }
@@ -696,7 +696,7 @@
       }
 
       continuing {
-        let tint_symbol_2 = array<f32, 1u>(2.0);
+        let tint_symbol_2 : array<f32, 1u> = array<f32, 1u>(2.0);
         f = (f + tint_symbol_2[runtime_value]);
       }
     }
@@ -728,11 +728,11 @@
   const arr_a = array<f32, 1u>(0.0);
   const arr_b = array<f32, 1u>(1.0);
   const arr_c = array<f32, 1u>(2.0);
-  let tint_symbol = arr_a;
+  let tint_symbol : array<f32, 1u> = arr_a;
   {
     var f = tint_symbol[runtime_value];
     loop {
-      let tint_symbol_1 = arr_b;
+      let tint_symbol_1 : array<f32, 1u> = arr_b;
       if (!((f < tint_symbol_1[runtime_value]))) {
         break;
       }
@@ -741,7 +741,7 @@
       }
 
       continuing {
-        let tint_symbol_2 = arr_c;
+        let tint_symbol_2 : array<f32, 1u> = arr_c;
         f = (f + tint_symbol_2[runtime_value]);
       }
     }
@@ -772,7 +772,7 @@
   if (true) {
     var marker = 0;
   } else {
-    let tint_symbol = array<f32, 2u>(f, f);
+    let tint_symbol : array<f32, 2u> = array<f32, 2u>(f, f);
     if ((f == tint_symbol[0])) {
       var marker = 1;
     }
@@ -813,11 +813,11 @@
   } else if (true) {
     var marker = 1;
   } else {
-    let tint_symbol = array<f32, 2u>(f, f);
+    let tint_symbol : array<f32, 2u> = array<f32, 2u>(f, f);
     if ((f == tint_symbol[0])) {
       var marker = 2;
     } else {
-      let tint_symbol_1 = array<f32, 2u>(f, f);
+      let tint_symbol_1 : array<f32, 2u> = array<f32, 2u>(f, f);
       if ((f == tint_symbol_1[1])) {
         var marker = 3;
       } else if (true) {
@@ -867,11 +867,11 @@
   } else if (true) {
     var marker = 1;
   } else {
-    let tint_symbol = arr;
+    let tint_symbol : array<f32, 2u> = arr;
     if ((f == tint_symbol[runtime_value])) {
       var marker = 2;
     } else {
-      let tint_symbol_1 = arr;
+      let tint_symbol_1 : array<f32, 2u> = arr;
       if ((f == tint_symbol_1[(runtime_value + 1)])) {
         var marker = 3;
       } else if (true) {
@@ -925,11 +925,11 @@
   } else if (true) {
     var marker = 1;
   } else {
-    let tint_symbol = arr;
+    let tint_symbol : array<f32, 2u> = arr;
     if ((f == tint_symbol[runtime_value])) {
       var marker = 2;
     } else {
-      let tint_symbol_1 = arr;
+      let tint_symbol_1 : array<f32, 2u> = arr;
       if ((f == tint_symbol_1[(runtime_value + 1)])) {
         var marker = 3;
       } else if (true) {
@@ -968,7 +968,7 @@
     auto* expect = R"(
 fn f() {
   let runtime_value = 1;
-  let tint_symbol = array<array<f32, 2u>, 2u>(array<f32, 2u>(1.0, 2.0), array<f32, 2u>(3.0, 4.0));
+  let tint_symbol : array<array<f32, 2u>, 2u> = array<array<f32, 2u>, 2u>(array<f32, 2u>(1.0, 2.0), array<f32, 2u>(3.0, 4.0));
   var i = tint_symbol[runtime_value][(runtime_value + 1)];
 }
 )";
@@ -1008,7 +1008,7 @@
   const arr_0 = array<f32, 2u>(1.0, 2.0);
   const arr_1 = array<f32, 2u>(3.0, 4.0);
   const arr_2 = array<array<f32, 2u>, 2u>(arr_0, arr_1);
-  let tint_symbol = arr_2;
+  let tint_symbol : array<array<f32, 2u>, 2u> = arr_2;
   var i = tint_symbol[runtime_value][(runtime_value + 1)];
 }
 )";
@@ -1041,7 +1041,7 @@
 
 fn f() {
   let runtime_value = 1;
-  let tint_symbol = arr_2;
+  let tint_symbol : array<array<f32, 2u>, 2u> = arr_2;
   var i = tint_symbol[runtime_value][(runtime_value + 1)];
 }
 )";
@@ -1096,7 +1096,7 @@
 }
 
 fn f() {
-  let tint_symbol = S3(S2(1, S1(2), 3));
+  let tint_symbol : S3 = S3(S2(1, S1(2), 3));
   var x = get_a(tint_symbol).b.a;
 }
 )";
@@ -1139,7 +1139,7 @@
 }
 
 fn f() {
-  let tint_symbol = S2(array<S1, 3u>(S1(1), S1(2), S1(3)));
+  let tint_symbol : S2 = S2(array<S1, 3u>(S1(1), S1(2), S1(3)));
   var x = get_a(tint_symbol)[1].a;
 }
 )";
@@ -1170,7 +1170,7 @@
 
     auto* expect = R"(
 fn f() {
-  let tint_symbol = S2(array<S1, 3u>(S1(1), S1(2), S1(3)));
+  let tint_symbol : S2 = S2(array<S1, 3u>(S1(1), S1(2), S1(3)));
   var x = get_a(tint_symbol)[1].a;
 }
 
@@ -1272,7 +1272,7 @@
       }
 
       continuing {
-        let tint_symbol = array<i32, 1u>(i);
+        let tint_symbol : array<i32, 1u> = array<i32, 1u>(i);
         f = (f + tint_symbol[0]);
       }
     }
@@ -1284,7 +1284,7 @@
   {
     var f = 0;
     loop {
-      let tint_symbol_1 = array<i32, 1u>(i);
+      let tint_symbol_1 : array<i32, 1u> = array<i32, 1u>(i);
       if (!((f < tint_symbol_1[0]))) {
         break;
       }
@@ -1301,7 +1301,7 @@
 
 fn Z() {
   var i = 10;
-  let tint_symbol_2 = array<i32, 1u>(i);
+  let tint_symbol_2 : array<i32, 1u> = array<i32, 1u>(i);
   for(var f = tint_symbol_2[0]; (f < 10); f = (f + 1)) {
     var i = 20;
   }
@@ -1313,5 +1313,27 @@
     EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(PromoteInitializersToLetTest, AssignAbstractArray) {
+    // Test that hoisting an array with abstract type still materializes to the correct type.
+    auto* src = R"(
+fn f() {
+  var arr : array<f32, 4>;
+  arr = array(1, 2, 3, 4);
+}
+)";
+
+    auto* expect = R"(
+fn f() {
+  var arr : array<f32, 4>;
+  let tint_symbol : array<f32, 4u> = array(1, 2, 3, 4);
+  arr = tint_symbol;
+}
+)";
+
+    auto got = Run<PromoteInitializersToLet>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace tint::transform
diff --git a/src/tint/transform/promote_side_effects_to_decl.cc b/src/tint/transform/promote_side_effects_to_decl.cc
index 15f4674..65ec731 100644
--- a/src/tint/transform/promote_side_effects_to_decl.cc
+++ b/src/tint/transform/promote_side_effects_to_decl.cc
@@ -284,7 +284,7 @@
                             return false;
                         }
                         // Don't hoist read-only variables as they cannot receive side-effects.
-                        if (var_user->Variable()->Access() == type::Access::kRead) {
+                        if (var_user->Variable()->Access() == builtin::Access::kRead) {
                             return false;
                         }
                         // Don't hoist textures / samplers as they can't be placed into a let, nor
diff --git a/src/tint/transform/remove_phonies.cc b/src/tint/transform/remove_phonies.cc
index 6131892..b6d877d 100644
--- a/src/tint/transform/remove_phonies.cc
+++ b/src/tint/transform/remove_phonies.cc
@@ -61,8 +61,8 @@
                     if (!ast::TraverseExpressions(
                             stmt->rhs, b.Diagnostics(), [&](const ast::CallExpression* expr) {
                                 // ast::CallExpression may map to a function or builtin call
-                                // (both may have side-effects), or a type initializer or
-                                // type conversion (both do not have side effects).
+                                // (both may have side-effects), or a value constructor or value
+                                // conversion (both do not have side effects).
                                 auto* call = sem.Get<sem::Call>(expr);
                                 if (!call) {
                                     // Semantic node must be a Materialize, in which case the
diff --git a/src/tint/transform/remove_phonies_test.cc b/src/tint/transform/remove_phonies_test.cc
index a072e51..dc91b5a 100644
--- a/src/tint/transform/remove_phonies_test.cc
+++ b/src/tint/transform/remove_phonies_test.cc
@@ -67,8 +67,6 @@
   _ = mat2x2<f32>(9.0, 10.0, 11.0, 12.0);
   _ = atan2(1.0, 2.0);
   _ = clamp(1.0, 2.0, 3.0);
-  atan2(1.0, 2.0);
-  clamp(1.0, 2.0, 3.0);
 }
 )";
 
diff --git a/src/tint/transform/renamer.cc b/src/tint/transform/renamer.cc
index f2aea29..3ddb6c6 100644
--- a/src/tint/transform/renamer.cc
+++ b/src/tint/transform/renamer.cc
@@ -21,9 +21,9 @@
 #include "src/tint/sem/builtin_enum_expression.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/member_accessor_expression.h"
-#include "src/tint/sem/type_conversion.h"
 #include "src/tint/sem/type_expression.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/text/unicode.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::Renamer);
@@ -1309,10 +1309,10 @@
                     [&](const sem::Builtin*) {
                         preserved_identifiers.Add(call->target->identifier);
                     },
-                    [&](const sem::TypeConversion*) {
+                    [&](const sem::ValueConversion*) {
                         preserve_if_builtin_type(call->target->identifier);
                     },
-                    [&](const sem::TypeInitializer*) {
+                    [&](const sem::ValueConstructor*) {
                         preserve_if_builtin_type(call->target->identifier);
                     });
             });
diff --git a/src/tint/transform/renamer_test.cc b/src/tint/transform/renamer_test.cc
index c233267..8ff6898 100644
--- a/src/tint/transform/renamer_test.cc
+++ b/src/tint/transform/renamer_test.cc
@@ -19,9 +19,9 @@
 #include <vector>
 
 #include "gmock/gmock.h"
+#include "src/tint/builtin/builtin.h"
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/transform/test_helper.h"
-#include "src/tint/type/builtin.h"
-#include "src/tint/type/texel_format.h"
 
 namespace tint::transform {
 namespace {
@@ -1711,7 +1711,7 @@
 
 std::vector<const char*> ConstructableTypes() {
     std::vector<const char*> out;
-    for (auto* ty : type::kBuiltinStrings) {
+    for (auto* ty : builtin::kBuiltinStrings) {
         std::string_view type(ty);
         if (type != "ptr" && type != "atomic" && !utils::HasPrefix(type, "sampler") &&
             !utils::HasPrefix(type, "texture")) {
@@ -1792,7 +1792,7 @@
 
 TEST_P(RenamerBuiltinTypeTest, PreserveTypeConversion) {
     if (std::string_view(GetParam()) == "array") {
-        return;  // Cannot type convert arrays.
+        return;  // Cannot value convert arrays.
     }
 
     auto expand = [&](const char* source) {
@@ -1856,7 +1856,7 @@
     };
 
     auto src = expand(R"(
-type $name = $other_type;
+alias $name = $other_type;
 
 @fragment
 fn f() {
@@ -1923,16 +1923,18 @@
 /// @return WGSL builtin identifier keywords
 std::vector<const char*> Identifiers() {
     std::vector<const char*> out;
-    for (auto* ident : type::kBuiltinStrings) {
+    for (auto* ident : builtin::kBuiltinStrings) {
         out.push_back(ident);
     }
-    for (auto* ident : type::kAddressSpaceStrings) {
+    for (auto* ident : builtin::kAddressSpaceStrings) {
+        if (!utils::HasPrefix(ident, "_")) {
+            out.push_back(ident);
+        }
+    }
+    for (auto* ident : builtin::kTexelFormatStrings) {
         out.push_back(ident);
     }
-    for (auto* ident : type::kTexelFormatStrings) {
-        out.push_back(ident);
-    }
-    for (auto* ident : type::kAccessStrings) {
+    for (auto* ident : builtin::kAccessStrings) {
         out.push_back(ident);
     }
     return out;
@@ -1940,24 +1942,24 @@
 
 using RenamerBuiltinIdentifierTest = TransformTestWithParam<const char*>;
 
-TEST_P(RenamerBuiltinIdentifierTest, GlobalVarName) {
+TEST_P(RenamerBuiltinIdentifierTest, GlobalConstName) {
     auto expand = [&](const char* source) {
         return utils::ReplaceAll(source, "$name", GetParam());
     };
 
     auto src = expand(R"(
-var<private> $name = 42;
+const $name = 42;
 
 fn f() {
-  var v = $name;
+  const v = $name;
 }
 )");
 
     auto expect = expand(R"(
-var<private> tint_symbol = 42;
+const tint_symbol = 42;
 
 fn tint_symbol_1() {
-  var tint_symbol_2 = tint_symbol;
+  const tint_symbol_2 = tint_symbol;
 }
 )");
 
diff --git a/src/tint/transform/robustness.cc b/src/tint/transform/robustness.cc
index 579d684..c6bf218 100644
--- a/src/tint/transform/robustness.cc
+++ b/src/tint/transform/robustness.cc
@@ -38,7 +38,7 @@
     /// Constructor
     /// @param program the source program
     /// @param omitted the omitted address spaces
-    State(const Program* program, std::unordered_set<type::AddressSpace>&& omitted)
+    State(const Program* program, std::unordered_set<builtin::AddressSpace>&& omitted)
         : src(program), omitted_address_spaces(std::move(omitted)) {}
 
     /// Runs the transform
@@ -60,7 +60,7 @@
     CloneContext ctx = {&b, src, /* auto_clone_symbols */ true};
 
     /// Set of address spaces to not apply the transform to
-    std::unordered_set<type::AddressSpace> omitted_address_spaces;
+    std::unordered_set<builtin::AddressSpace> omitted_address_spaces;
 
     /// Apply bounds clamping to array, vector and matrix indexing
     /// @param expr the array, vector or matrix index expression
@@ -294,14 +294,14 @@
         cfg = *cfg_data;
     }
 
-    std::unordered_set<type::AddressSpace> omitted_address_spaces;
+    std::unordered_set<builtin::AddressSpace> omitted_address_spaces;
     for (auto sc : cfg.omitted_address_spaces) {
         switch (sc) {
             case AddressSpace::kUniform:
-                omitted_address_spaces.insert(type::AddressSpace::kUniform);
+                omitted_address_spaces.insert(builtin::AddressSpace::kUniform);
                 break;
             case AddressSpace::kStorage:
-                omitted_address_spaces.insert(type::AddressSpace::kStorage);
+                omitted_address_spaces.insert(builtin::AddressSpace::kStorage);
                 break;
         }
     }
diff --git a/src/tint/transform/robustness_test.cc b/src/tint/transform/robustness_test.cc
index 8b9a8ad..9bb9527 100644
--- a/src/tint/transform/robustness_test.cc
+++ b/src/tint/transform/robustness_test.cc
@@ -792,14 +792,14 @@
   var level_idx : i32;
   var sample_idx : i32;
 
-  textureLoad(tex_1d, 1i, level_idx);
-  textureLoad(tex_2d, vec2<i32>(1, 2), level_idx);
-  textureLoad(tex_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
-  textureLoad(tex_3d, vec3<i32>(1, 2, 3), level_idx);
-  textureLoad(tex_ms_2d, vec2<i32>(1, 2), sample_idx);
-  textureLoad(tex_depth_2d, vec2<i32>(1, 2), level_idx);
-  textureLoad(tex_depth_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
-  textureLoad(tex_external, vec2<i32>(1, 2));
+  _ = textureLoad(tex_1d, 1i, level_idx);
+  _ = textureLoad(tex_2d, vec2<i32>(1, 2), level_idx);
+  _ = textureLoad(tex_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
+  _ = textureLoad(tex_3d, vec3<i32>(1, 2, 3), level_idx);
+  _ = textureLoad(tex_ms_2d, vec2<i32>(1, 2), sample_idx);
+  _ = textureLoad(tex_depth_2d, vec2<i32>(1, 2), level_idx);
+  _ = textureLoad(tex_depth_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
+  _ = textureLoad(tex_external, vec2<i32>(1, 2));
 }
 
 fn idx_unsigned() {
@@ -807,14 +807,14 @@
   var level_idx : u32;
   var sample_idx : u32;
 
-  textureLoad(tex_1d, 1u, level_idx);
-  textureLoad(tex_2d, vec2<u32>(1, 2), level_idx);
-  textureLoad(tex_2d_arr, vec2<u32>(1, 2), array_idx, level_idx);
-  textureLoad(tex_3d, vec3<u32>(1, 2, 3), level_idx);
-  textureLoad(tex_ms_2d, vec2<u32>(1, 2), sample_idx);
-  textureLoad(tex_depth_2d, vec2<u32>(1, 2), level_idx);
-  textureLoad(tex_depth_2d_arr, vec2<u32>(1, 2), array_idx, level_idx);
-  textureLoad(tex_external, vec2<u32>(1, 2));
+  _ = textureLoad(tex_1d, 1u, level_idx);
+  _ = textureLoad(tex_2d, vec2<u32>(1, 2), level_idx);
+  _ = textureLoad(tex_2d_arr, vec2<u32>(1, 2), array_idx, level_idx);
+  _ = textureLoad(tex_3d, vec3<u32>(1, 2, 3), level_idx);
+  _ = textureLoad(tex_ms_2d, vec2<u32>(1, 2), sample_idx);
+  _ = textureLoad(tex_depth_2d, vec2<u32>(1, 2), level_idx);
+  _ = textureLoad(tex_depth_2d_arr, vec2<u32>(1, 2), array_idx, level_idx);
+  _ = textureLoad(tex_external, vec2<u32>(1, 2));
 }
 )";
 
@@ -840,28 +840,28 @@
   var array_idx : i32;
   var level_idx : i32;
   var sample_idx : i32;
-  textureLoad(tex_1d, clamp(1i, 0, i32((u32(textureDimensions(tex_1d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_1d)) - 1))))) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_1d)) - 1))));
-  textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_2d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d)) - 1))))) - vec2(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d)) - 1))));
-  textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_2d_arr, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d_arr)) - 1))))) - vec2(1)))), clamp(array_idx, 0, i32((u32(textureNumLayers(tex_2d_arr)) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d_arr)) - 1))));
-  textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3(0), vec3<i32>((vec3<u32>(textureDimensions(tex_3d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_3d)) - 1))))) - vec3(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_3d)) - 1))));
-  textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_ms_2d)) - vec2(1)))), sample_idx);
-  textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_depth_2d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d)) - 1))))) - vec2(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d)) - 1))));
-  textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d_arr)) - 1))))) - vec2(1)))), clamp(array_idx, 0, i32((u32(textureNumLayers(tex_depth_2d_arr)) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d_arr)) - 1))));
-  textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_external)) - vec2(1)))));
+  _ = textureLoad(tex_1d, clamp(1i, 0, i32((u32(textureDimensions(tex_1d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_1d)) - 1))))) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_1d)) - 1))));
+  _ = textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_2d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d)) - 1))))) - vec2(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d)) - 1))));
+  _ = textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_2d_arr, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d_arr)) - 1))))) - vec2(1)))), clamp(array_idx, 0, i32((u32(textureNumLayers(tex_2d_arr)) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d_arr)) - 1))));
+  _ = textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3(0), vec3<i32>((vec3<u32>(textureDimensions(tex_3d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_3d)) - 1))))) - vec3(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_3d)) - 1))));
+  _ = textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_ms_2d)) - vec2(1)))), sample_idx);
+  _ = textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_depth_2d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d)) - 1))))) - vec2(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d)) - 1))));
+  _ = textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d_arr)) - 1))))) - vec2(1)))), clamp(array_idx, 0, i32((u32(textureNumLayers(tex_depth_2d_arr)) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d_arr)) - 1))));
+  _ = textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_external)) - vec2(1)))));
 }
 
 fn idx_unsigned() {
   var array_idx : u32;
   var level_idx : u32;
   var sample_idx : u32;
-  textureLoad(tex_1d, min(1u, (u32(textureDimensions(tex_1d, min(level_idx, (u32(textureNumLevels(tex_1d)) - 1)))) - 1)), min(level_idx, (u32(textureNumLevels(tex_1d)) - 1)));
-  textureLoad(tex_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_2d, min(level_idx, (u32(textureNumLevels(tex_2d)) - 1)))) - vec2(1))), min(level_idx, (u32(textureNumLevels(tex_2d)) - 1)));
-  textureLoad(tex_2d_arr, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_2d_arr, min(level_idx, (u32(textureNumLevels(tex_2d_arr)) - 1)))) - vec2(1))), min(array_idx, (u32(textureNumLayers(tex_2d_arr)) - 1)), min(level_idx, (u32(textureNumLevels(tex_2d_arr)) - 1)));
-  textureLoad(tex_3d, min(vec3<u32>(1, 2, 3), (vec3<u32>(textureDimensions(tex_3d, min(level_idx, (u32(textureNumLevels(tex_3d)) - 1)))) - vec3(1))), min(level_idx, (u32(textureNumLevels(tex_3d)) - 1)));
-  textureLoad(tex_ms_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_ms_2d)) - vec2(1))), sample_idx);
-  textureLoad(tex_depth_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_depth_2d, min(level_idx, (u32(textureNumLevels(tex_depth_2d)) - 1)))) - vec2(1))), min(level_idx, (u32(textureNumLevels(tex_depth_2d)) - 1)));
-  textureLoad(tex_depth_2d_arr, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_depth_2d_arr, min(level_idx, (u32(textureNumLevels(tex_depth_2d_arr)) - 1)))) - vec2(1))), min(array_idx, (u32(textureNumLayers(tex_depth_2d_arr)) - 1)), min(level_idx, (u32(textureNumLevels(tex_depth_2d_arr)) - 1)));
-  textureLoad(tex_external, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_external)) - vec2(1))));
+  _ = textureLoad(tex_1d, min(1u, (u32(textureDimensions(tex_1d, min(level_idx, (u32(textureNumLevels(tex_1d)) - 1)))) - 1)), min(level_idx, (u32(textureNumLevels(tex_1d)) - 1)));
+  _ = textureLoad(tex_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_2d, min(level_idx, (u32(textureNumLevels(tex_2d)) - 1)))) - vec2(1))), min(level_idx, (u32(textureNumLevels(tex_2d)) - 1)));
+  _ = textureLoad(tex_2d_arr, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_2d_arr, min(level_idx, (u32(textureNumLevels(tex_2d_arr)) - 1)))) - vec2(1))), min(array_idx, (u32(textureNumLayers(tex_2d_arr)) - 1)), min(level_idx, (u32(textureNumLevels(tex_2d_arr)) - 1)));
+  _ = textureLoad(tex_3d, min(vec3<u32>(1, 2, 3), (vec3<u32>(textureDimensions(tex_3d, min(level_idx, (u32(textureNumLevels(tex_3d)) - 1)))) - vec3(1))), min(level_idx, (u32(textureNumLevels(tex_3d)) - 1)));
+  _ = textureLoad(tex_ms_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_ms_2d)) - vec2(1))), sample_idx);
+  _ = textureLoad(tex_depth_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_depth_2d, min(level_idx, (u32(textureNumLevels(tex_depth_2d)) - 1)))) - vec2(1))), min(level_idx, (u32(textureNumLevels(tex_depth_2d)) - 1)));
+  _ = textureLoad(tex_depth_2d_arr, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_depth_2d_arr, min(level_idx, (u32(textureNumLevels(tex_depth_2d_arr)) - 1)))) - vec2(1))), min(array_idx, (u32(textureNumLayers(tex_depth_2d_arr)) - 1)), min(level_idx, (u32(textureNumLevels(tex_depth_2d_arr)) - 1)));
+  _ = textureLoad(tex_external, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_external)) - vec2(1))));
 }
 )";
 
@@ -878,14 +878,14 @@
   var level_idx : i32;
   var sample_idx : i32;
 
-  textureLoad(tex_1d, 1i, level_idx);
-  textureLoad(tex_2d, vec2<i32>(1, 2), level_idx);
-  textureLoad(tex_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
-  textureLoad(tex_3d, vec3<i32>(1, 2, 3), level_idx);
-  textureLoad(tex_ms_2d, vec2<i32>(1, 2), sample_idx);
-  textureLoad(tex_depth_2d, vec2<i32>(1, 2), level_idx);
-  textureLoad(tex_depth_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
-  textureLoad(tex_external, vec2<i32>(1, 2));
+  _ = textureLoad(tex_1d, 1i, level_idx);
+  _ = textureLoad(tex_2d, vec2<i32>(1, 2), level_idx);
+  _ = textureLoad(tex_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
+  _ = textureLoad(tex_3d, vec3<i32>(1, 2, 3), level_idx);
+  _ = textureLoad(tex_ms_2d, vec2<i32>(1, 2), sample_idx);
+  _ = textureLoad(tex_depth_2d, vec2<i32>(1, 2), level_idx);
+  _ = textureLoad(tex_depth_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
+  _ = textureLoad(tex_external, vec2<i32>(1, 2));
 }
 
 fn idx_unsigned() {
@@ -893,14 +893,14 @@
   var level_idx : u32;
   var sample_idx : u32;
 
-  textureLoad(tex_1d, 1u, level_idx);
-  textureLoad(tex_2d, vec2<u32>(1, 2), level_idx);
-  textureLoad(tex_2d_arr, vec2<u32>(1, 2), array_idx, level_idx);
-  textureLoad(tex_3d, vec3<u32>(1, 2, 3), level_idx);
-  textureLoad(tex_ms_2d, vec2<u32>(1, 2), sample_idx);
-  textureLoad(tex_depth_2d, vec2<u32>(1, 2), level_idx);
-  textureLoad(tex_depth_2d_arr, vec2<u32>(1, 2), array_idx, level_idx);
-  textureLoad(tex_external, vec2<u32>(1, 2));
+  _ = textureLoad(tex_1d, 1u, level_idx);
+  _ = textureLoad(tex_2d, vec2<u32>(1, 2), level_idx);
+  _ = textureLoad(tex_2d_arr, vec2<u32>(1, 2), array_idx, level_idx);
+  _ = textureLoad(tex_3d, vec3<u32>(1, 2, 3), level_idx);
+  _ = textureLoad(tex_ms_2d, vec2<u32>(1, 2), sample_idx);
+  _ = textureLoad(tex_depth_2d, vec2<u32>(1, 2), level_idx);
+  _ = textureLoad(tex_depth_2d_arr, vec2<u32>(1, 2), array_idx, level_idx);
+  _ = textureLoad(tex_external, vec2<u32>(1, 2));
 }
 
 @group(0) @binding(0) var tex_1d : texture_1d<f32>;
@@ -919,28 +919,28 @@
   var array_idx : i32;
   var level_idx : i32;
   var sample_idx : i32;
-  textureLoad(tex_1d, clamp(1i, 0, i32((u32(textureDimensions(tex_1d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_1d)) - 1))))) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_1d)) - 1))));
-  textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_2d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d)) - 1))))) - vec2(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d)) - 1))));
-  textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_2d_arr, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d_arr)) - 1))))) - vec2(1)))), clamp(array_idx, 0, i32((u32(textureNumLayers(tex_2d_arr)) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d_arr)) - 1))));
-  textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3(0), vec3<i32>((vec3<u32>(textureDimensions(tex_3d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_3d)) - 1))))) - vec3(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_3d)) - 1))));
-  textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_ms_2d)) - vec2(1)))), sample_idx);
-  textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_depth_2d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d)) - 1))))) - vec2(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d)) - 1))));
-  textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d_arr)) - 1))))) - vec2(1)))), clamp(array_idx, 0, i32((u32(textureNumLayers(tex_depth_2d_arr)) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d_arr)) - 1))));
-  textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_external)) - vec2(1)))));
+  _ = textureLoad(tex_1d, clamp(1i, 0, i32((u32(textureDimensions(tex_1d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_1d)) - 1))))) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_1d)) - 1))));
+  _ = textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_2d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d)) - 1))))) - vec2(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d)) - 1))));
+  _ = textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_2d_arr, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d_arr)) - 1))))) - vec2(1)))), clamp(array_idx, 0, i32((u32(textureNumLayers(tex_2d_arr)) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_2d_arr)) - 1))));
+  _ = textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3(0), vec3<i32>((vec3<u32>(textureDimensions(tex_3d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_3d)) - 1))))) - vec3(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_3d)) - 1))));
+  _ = textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_ms_2d)) - vec2(1)))), sample_idx);
+  _ = textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_depth_2d, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d)) - 1))))) - vec2(1)))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d)) - 1))));
+  _ = textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d_arr)) - 1))))) - vec2(1)))), clamp(array_idx, 0, i32((u32(textureNumLayers(tex_depth_2d_arr)) - 1))), clamp(level_idx, 0, i32((u32(textureNumLevels(tex_depth_2d_arr)) - 1))));
+  _ = textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_external)) - vec2(1)))));
 }
 
 fn idx_unsigned() {
   var array_idx : u32;
   var level_idx : u32;
   var sample_idx : u32;
-  textureLoad(tex_1d, min(1u, (u32(textureDimensions(tex_1d, min(level_idx, (u32(textureNumLevels(tex_1d)) - 1)))) - 1)), min(level_idx, (u32(textureNumLevels(tex_1d)) - 1)));
-  textureLoad(tex_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_2d, min(level_idx, (u32(textureNumLevels(tex_2d)) - 1)))) - vec2(1))), min(level_idx, (u32(textureNumLevels(tex_2d)) - 1)));
-  textureLoad(tex_2d_arr, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_2d_arr, min(level_idx, (u32(textureNumLevels(tex_2d_arr)) - 1)))) - vec2(1))), min(array_idx, (u32(textureNumLayers(tex_2d_arr)) - 1)), min(level_idx, (u32(textureNumLevels(tex_2d_arr)) - 1)));
-  textureLoad(tex_3d, min(vec3<u32>(1, 2, 3), (vec3<u32>(textureDimensions(tex_3d, min(level_idx, (u32(textureNumLevels(tex_3d)) - 1)))) - vec3(1))), min(level_idx, (u32(textureNumLevels(tex_3d)) - 1)));
-  textureLoad(tex_ms_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_ms_2d)) - vec2(1))), sample_idx);
-  textureLoad(tex_depth_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_depth_2d, min(level_idx, (u32(textureNumLevels(tex_depth_2d)) - 1)))) - vec2(1))), min(level_idx, (u32(textureNumLevels(tex_depth_2d)) - 1)));
-  textureLoad(tex_depth_2d_arr, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_depth_2d_arr, min(level_idx, (u32(textureNumLevels(tex_depth_2d_arr)) - 1)))) - vec2(1))), min(array_idx, (u32(textureNumLayers(tex_depth_2d_arr)) - 1)), min(level_idx, (u32(textureNumLevels(tex_depth_2d_arr)) - 1)));
-  textureLoad(tex_external, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_external)) - vec2(1))));
+  _ = textureLoad(tex_1d, min(1u, (u32(textureDimensions(tex_1d, min(level_idx, (u32(textureNumLevels(tex_1d)) - 1)))) - 1)), min(level_idx, (u32(textureNumLevels(tex_1d)) - 1)));
+  _ = textureLoad(tex_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_2d, min(level_idx, (u32(textureNumLevels(tex_2d)) - 1)))) - vec2(1))), min(level_idx, (u32(textureNumLevels(tex_2d)) - 1)));
+  _ = textureLoad(tex_2d_arr, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_2d_arr, min(level_idx, (u32(textureNumLevels(tex_2d_arr)) - 1)))) - vec2(1))), min(array_idx, (u32(textureNumLayers(tex_2d_arr)) - 1)), min(level_idx, (u32(textureNumLevels(tex_2d_arr)) - 1)));
+  _ = textureLoad(tex_3d, min(vec3<u32>(1, 2, 3), (vec3<u32>(textureDimensions(tex_3d, min(level_idx, (u32(textureNumLevels(tex_3d)) - 1)))) - vec3(1))), min(level_idx, (u32(textureNumLevels(tex_3d)) - 1)));
+  _ = textureLoad(tex_ms_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_ms_2d)) - vec2(1))), sample_idx);
+  _ = textureLoad(tex_depth_2d, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_depth_2d, min(level_idx, (u32(textureNumLevels(tex_depth_2d)) - 1)))) - vec2(1))), min(level_idx, (u32(textureNumLevels(tex_depth_2d)) - 1)));
+  _ = textureLoad(tex_depth_2d_arr, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_depth_2d_arr, min(level_idx, (u32(textureNumLevels(tex_depth_2d_arr)) - 1)))) - vec2(1))), min(array_idx, (u32(textureNumLayers(tex_depth_2d_arr)) - 1)), min(level_idx, (u32(textureNumLevels(tex_depth_2d_arr)) - 1)));
+  _ = textureLoad(tex_external, min(vec2<u32>(1, 2), (vec2<u32>(textureDimensions(tex_external)) - vec2(1))));
 }
 
 @group(0) @binding(0) var tex_1d : texture_1d<f32>;
diff --git a/src/tint/transform/single_entry_point_test.cc b/src/tint/transform/single_entry_point_test.cc
index d0c3dd4..f4f1dec 100644
--- a/src/tint/transform/single_entry_point_test.cc
+++ b/src/tint/transform/single_entry_point_test.cc
@@ -416,7 +416,7 @@
 
 // This is all unused by the target entry point.
 @id(1) override c1 : u32;
-type arr_ty = array<i32, c1>;
+alias arr_ty = array<i32, c1>;
 var<workgroup> arr : arr_ty;
 
 @compute @workgroup_size(64)
diff --git a/src/tint/transform/spirv_atomic_test.cc b/src/tint/transform/spirv_atomic_test.cc
index bef061c..7bb9f2a 100644
--- a/src/tint/transform/spirv_atomic_test.cc
+++ b/src/tint/transform/spirv_atomic_test.cc
@@ -210,13 +210,13 @@
 
 TEST_F(SpirvAtomicTest, AliasedArraysOfU32) {
     auto* src = R"(
-type A0 = u32;
+alias A0 = u32;
 
-type A1 = array<A0, 1>;
+alias A1 = array<A0, 1>;
 
-type A2 = array<A1, 2>;
+alias A2 = array<A1, 2>;
 
-type A3 = array<A2, 3>;
+alias A3 = array<A2, 3>;
 
 var<workgroup> wg : A3;
 
diff --git a/src/tint/transform/std140.cc b/src/tint/transform/std140.cc
index 4c487d0..7a9cffc 100644
--- a/src/tint/transform/std140.cc
+++ b/src/tint/transform/std140.cc
@@ -144,7 +144,7 @@
         // Scan structures for members that need forking
         for (auto* ty : src->Types()) {
             if (auto* str = ty->As<sem::Struct>()) {
-                if (str->UsedAs(type::AddressSpace::kUniform)) {
+                if (str->UsedAs(builtin::AddressSpace::kUniform)) {
                     for (auto* member : str->Members()) {
                         if (needs_fork(member->Type())) {
                             return true;
@@ -157,7 +157,7 @@
         // Scan uniform variables that have types that need forking
         for (auto* decl : src->AST().GlobalVariables()) {
             auto* global = src->Sem().Get(decl);
-            if (global->AddressSpace() == type::AddressSpace::kUniform) {
+            if (global->AddressSpace() == builtin::AddressSpace::kUniform) {
                 if (needs_fork(global->Type()->UnwrapRef())) {
                     return true;
                 }
@@ -280,7 +280,7 @@
         for (auto* global : src->Sem().Module()->DependencyOrderedDeclarations()) {
             // Check to see if this is a structure used by a uniform buffer...
             auto* str = sem.Get<sem::Struct>(global);
-            if (str && str->UsedAs(type::AddressSpace::kUniform)) {
+            if (str && str->UsedAs(builtin::AddressSpace::kUniform)) {
                 // Should this uniform buffer be forked for std140 usage?
                 bool fork_std140 = false;
                 utils::Vector<const ast::StructMember*, 8> members;
@@ -350,8 +350,8 @@
     void ReplaceUniformVarTypes() {
         for (auto* global : src->AST().GlobalVariables()) {
             if (auto* var = global->As<ast::Var>()) {
-                if (var->declared_address_space == type::AddressSpace::kUniform) {
-                    auto* v = sem.Get(var);
+                auto* v = sem.Get(var);
+                if (v->AddressSpace() == builtin::AddressSpace::kUniform) {
                     if (auto std140_ty = Std140Type(v->Type()->UnwrapRef())) {
                         ctx.Replace(global->type.expr, b.Expr(std140_ty));
                         std140_uniforms.Add(v);
diff --git a/src/tint/transform/texture_1d_to_2d_test.cc b/src/tint/transform/texture_1d_to_2d_test.cc
index 5a2cd18..0196951 100644
--- a/src/tint/transform/texture_1d_to_2d_test.cc
+++ b/src/tint/transform/texture_1d_to_2d_test.cc
@@ -142,14 +142,14 @@
 @group(0) @binding(0) var t : texture_1d<f32>;
 
 fn main() {
-  textureDimensions(t);
+  _ = textureDimensions(t);
 }
 )";
     auto* expect = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
 
 fn main() {
-  textureDimensions(t);
+  _ = textureDimensions(t).x;
 }
 )";
 
@@ -276,7 +276,7 @@
 @group(0) @binding(0) var tex : texture_1d<i32>;
 
 fn d() {
-  textureLoad(tex, 1, 0);
+  _ = textureLoad(tex, 1, 0);
   let l = sin(3.0);
 }
 )";
@@ -285,7 +285,7 @@
 @group(0) @binding(0) var tex : texture_2d<i32>;
 
 fn d() {
-  textureLoad(tex, vec2<i32>(1, 0), 0);
+  _ = textureLoad(tex, vec2<i32>(1, 0), 0);
   let l = sin(3.0);
 }
 )";
diff --git a/src/tint/transform/transform.h b/src/tint/transform/transform.h
index dfb9188..c9c1eee 100644
--- a/src/tint/transform/transform.h
+++ b/src/tint/transform/transform.h
@@ -181,6 +181,12 @@
                               const DataMap& inputs,
                               DataMap& outputs) const = 0;
 
+    /// CreateASTTypeFor constructs new ast::Type that reconstructs the semantic type `ty`.
+    /// @param ctx the clone context
+    /// @param ty the semantic type to reconstruct
+    /// @returns an ast::Type that when resolved, will produce the semantic type `ty`.
+    static ast::Type CreateASTTypeFor(CloneContext& ctx, const type::Type* ty);
+
   protected:
     /// Removes the statement `stmt` from the transformed program.
     /// RemoveStatement handles edge cases, like statements in the initializer and
@@ -188,12 +194,6 @@
     /// @param ctx the clone context
     /// @param stmt the statement to remove when the program is cloned
     static void RemoveStatement(CloneContext& ctx, const ast::Statement* stmt);
-
-    /// CreateASTTypeFor constructs new ast::Type that reconstructs the semantic type `ty`.
-    /// @param ctx the clone context
-    /// @param ty the semantic type to reconstruct
-    /// @returns an ast::Type that when resolved, will produce the semantic type `ty`.
-    static ast::Type CreateASTTypeFor(CloneContext& ctx, const type::Type* ty);
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/unshadow_test.cc b/src/tint/transform/unshadow_test.cc
index ec17ff5..9d8541d 100644
--- a/src/tint/transform/unshadow_test.cc
+++ b/src/tint/transform/unshadow_test.cc
@@ -50,7 +50,7 @@
 
 TEST_F(UnshadowTest, LocalShadowsAlias) {
     auto* src = R"(
-type a = i32;
+alias a = i32;
 
 fn X() {
   var a = false;
@@ -100,7 +100,7 @@
   const a = true;
 }
 
-type a = i32;
+alias a = i32;
 )";
 
     auto* expect = R"(
@@ -691,7 +691,7 @@
 
 TEST_F(UnshadowTest, ParamShadowsAlias) {
     auto* src = R"(
-type a = i32;
+alias a = i32;
 
 fn F(a : a) {
   {
@@ -732,7 +732,7 @@
   }
 }
 
-type a = i32;
+alias a = i32;
 )";
 
     auto* expect = R"(
diff --git a/src/tint/transform/utils/hoist_to_decl_before.cc b/src/tint/transform/utils/hoist_to_decl_before.cc
index fd7402e..28f6b36 100644
--- a/src/tint/transform/utils/hoist_to_decl_before.cc
+++ b/src/tint/transform/utils/hoist_to_decl_before.cc
@@ -45,7 +45,9 @@
         switch (kind) {
             case VariableKind::kLet: {
                 auto builder = [this, expr, name] {
-                    return b.Decl(b.Let(name, ctx.CloneWithoutTransform(expr)));
+                    return b.Decl(b.Let(
+                        name, Transform::CreateASTTypeFor(ctx, ctx.src->Sem().GetVal(expr)->Type()),
+                        ctx.CloneWithoutTransform(expr)));
                 };
                 if (!InsertBeforeImpl(before_expr->Stmt(), std::move(builder))) {
                     return false;
@@ -55,7 +57,9 @@
 
             case VariableKind::kVar: {
                 auto builder = [this, expr, name] {
-                    return b.Decl(b.Var(name, ctx.CloneWithoutTransform(expr)));
+                    return b.Decl(b.Var(
+                        name, Transform::CreateASTTypeFor(ctx, ctx.src->Sem().GetVal(expr)->Type()),
+                        ctx.CloneWithoutTransform(expr)));
                 };
                 if (!InsertBeforeImpl(before_expr->Stmt(), std::move(builder))) {
                     return false;
diff --git a/src/tint/transform/utils/hoist_to_decl_before_test.cc b/src/tint/transform/utils/hoist_to_decl_before_test.cc
index 8f16675..e8d92ed 100644
--- a/src/tint/transform/utils/hoist_to_decl_before_test.cc
+++ b/src/tint/transform/utils/hoist_to_decl_before_test.cc
@@ -51,7 +51,7 @@
 
     auto* expect = R"(
 fn f() {
-  let tint_symbol = 1i;
+  let tint_symbol : i32 = 1i;
   var a = tint_symbol;
 }
 )";
@@ -82,7 +82,7 @@
 
     auto* expect = R"(
 fn f() {
-  var tint_symbol = 1i;
+  var tint_symbol : i32 = 1i;
   for(var a = tint_symbol; true; ) {
   }
 }
@@ -162,7 +162,7 @@
     }
 
     continuing {
-      let tint_symbol = 1i;
+      let tint_symbol : i32 = 1i;
       var a = tint_symbol;
     }
   }
@@ -199,7 +199,7 @@
 fn f() {
   var a : bool;
   loop {
-    var tint_symbol = a;
+    var tint_symbol : bool = a;
     if (!(tint_symbol)) {
       break;
     }
@@ -280,7 +280,7 @@
     auto* expect = R"(
 fn f() {
   var a : array<i32, 10u>;
-  let tint_symbol = a[0i];
+  let tint_symbol : i32 = a[0i];
   var b = tint_symbol;
 }
 )";
@@ -314,7 +314,7 @@
     auto* expect = R"(
 fn f() {
   var a : array<array<i32, 10u>, 10i>;
-  var tint_symbol = a[0i][0i];
+  var tint_symbol : i32 = a[0i][0i];
   var b = tint_symbol;
 }
 )";
@@ -793,5 +793,65 @@
     EXPECT_EQ(expect, str(cloned));
 }
 
+TEST_F(HoistToDeclBeforeTest, AbstractArray_ToLet) {
+    // fn f() {
+    //     var a : array<f32, 1> = array(1);
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Call(b.ty("array"), b.Expr(1_a));
+    auto* var = b.Decl(b.Var("a", b.ty.array(b.ty.f32(), 1_a), expr));
+    b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var});
+
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
+
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, HoistToDeclBefore::VariableKind::kLet);
+
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
+
+    auto* expect = R"(
+fn f() {
+  let tint_symbol : array<f32, 1u> = array(1);
+  var a : array<f32, 1> = tint_symbol;
+}
+)";
+
+    EXPECT_EQ(expect, str(cloned));
+}
+
+TEST_F(HoistToDeclBeforeTest, AbstractArray_ToVar) {
+    // fn f() {
+    //     var a : array<f32, 1> = array(1);
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Call(b.ty("array"), b.Expr(1_a));
+    auto* var = b.Decl(b.Var("a", b.ty.array(b.ty.f32(), 1_a), expr));
+    b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var});
+
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
+
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, HoistToDeclBefore::VariableKind::kVar);
+
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
+
+    auto* expect = R"(
+fn f() {
+  var tint_symbol : array<f32, 1u> = array(1);
+  var a : array<f32, 1> = tint_symbol;
+}
+)";
+
+    EXPECT_EQ(expect, str(cloned));
+}
+
 }  // namespace
 }  // namespace tint::transform
diff --git a/src/tint/transform/var_for_dynamic_index_test.cc b/src/tint/transform/var_for_dynamic_index_test.cc
index 05c19b3..80a79d5 100644
--- a/src/tint/transform/var_for_dynamic_index_test.cc
+++ b/src/tint/transform/var_for_dynamic_index_test.cc
@@ -44,7 +44,7 @@
 fn f() {
   var i : i32;
   let p = array<i32, 4>(1, 2, 3, 4);
-  var var_for_index = p;
+  var var_for_index : array<i32, 4u> = p;
   let x = var_for_index[i];
 }
 )";
@@ -68,7 +68,7 @@
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
-  var var_for_index = p;
+  var var_for_index : mat2x2<f32> = p;
   let x = var_for_index[i];
 }
 )";
@@ -99,8 +99,8 @@
   var i : i32;
   var j : i32;
   let p = array<array<i32, 2>, 2>(array<i32, 2>(1, 2), array<i32, 2>(3, 4));
-  var var_for_index = p;
-  var var_for_index_1 = var_for_index[i];
+  var var_for_index : array<array<i32, 2u>, 2u> = p;
+  var var_for_index_1 : array<i32, 2u> = var_for_index[i];
   let x = var_for_index_1[j];
 }
 )";
@@ -126,7 +126,7 @@
 fn f() {
   var i : i32;
   let p = array<array<i32, 2>, 2>(array<i32, 2>(1, 2), array<i32, 2>(3, 4));
-  var var_for_index = p;
+  var var_for_index : array<array<i32, 2u>, 2u> = p;
   for(let x = var_for_index[i]; ; ) {
     break;
   }
@@ -154,7 +154,7 @@
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
-  var var_for_index = p;
+  var var_for_index : mat2x2<f32> = p;
   for(let x = var_for_index[i]; ; ) {
     break;
   }
@@ -183,7 +183,7 @@
   var i : i32;
   let p = array<i32, 2>(1, 2);
   loop {
-    var var_for_index = p;
+    var var_for_index : array<i32, 2u> = p;
     if (!((var_for_index[i] < 3))) {
       break;
     }
@@ -216,7 +216,7 @@
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
   loop {
-    var var_for_index = p;
+    var var_for_index : mat2x2<f32> = p;
     if (!((var_for_index[i].x < 3.0))) {
       break;
     }
@@ -252,12 +252,12 @@
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
   loop {
-    var var_for_index = p;
+    var var_for_index : mat2x2<f32> = p;
     if (!((var_for_index[i].x < 3.0))) {
       break;
     }
     {
-      var var_for_index_1 = p;
+      var var_for_index_1 : mat2x2<f32> = p;
       if ((var_for_index_1[i].x < 1.0)) {
         var marker = 1;
       }
@@ -293,7 +293,7 @@
   if (false) {
     var marker = 0;
   } else {
-    var var_for_index = p;
+    var var_for_index : array<i32, 2u> = p;
     if ((var_for_index[i] < 3)) {
       var marker = 1;
     }
@@ -337,11 +337,11 @@
   } else if (true) {
     var marker = 1;
   } else {
-    var var_for_index = p;
+    var var_for_index : array<i32, 2u> = p;
     if ((var_for_index[i] < 3)) {
       var marker = 2;
     } else {
-      var var_for_index_1 = p;
+      var var_for_index_1 : array<i32, 2u> = p;
       if ((var_for_index_1[i] < 4)) {
         var marker = 3;
       } else if (true) {
@@ -380,7 +380,7 @@
   if (false) {
     var marker_if = 1;
   } else {
-    var var_for_index = p;
+    var var_for_index : mat2x2<f32> = p;
     if ((var_for_index[i].x < 3.0)) {
       var marker_else_if = 1;
     }
@@ -424,11 +424,11 @@
   } else if (true) {
     var marker = 1;
   } else {
-    var var_for_index = p;
+    var var_for_index : mat2x2<f32> = p;
     if ((var_for_index[i].x < 3.0)) {
       var marker = 2;
     } else {
-      var var_for_index_1 = p;
+      var var_for_index_1 : mat2x2<f32> = p;
       if ((var_for_index_1[i].y < 3.0)) {
         var marker = 3;
       } else if (true) {
diff --git a/src/tint/transform/vectorize_matrix_conversions.cc b/src/tint/transform/vectorize_matrix_conversions.cc
index e920417..748346e 100644
--- a/src/tint/transform/vectorize_matrix_conversions.cc
+++ b/src/tint/transform/vectorize_matrix_conversions.cc
@@ -20,7 +20,7 @@
 
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/type_conversion.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/value_expression.h"
 #include "src/tint/type/abstract_numeric.h"
 #include "src/tint/utils/hash.h"
@@ -36,7 +36,8 @@
     for (auto* node : program->ASTNodes().Objects()) {
         if (auto* sem = program->Sem().GetVal(node)) {
             if (auto* call = sem->UnwrapMaterialize()->As<sem::Call>()) {
-                if (call->Target()->Is<sem::TypeConversion>() && call->Type()->Is<type::Matrix>()) {
+                if (call->Target()->Is<sem::ValueConversion>() &&
+                    call->Type()->Is<type::Matrix>()) {
                     auto& args = call->Arguments();
                     if (args.Length() == 1 && args[0]->Type()->UnwrapRef()->is_float_matrix()) {
                         return true;
@@ -71,7 +72,7 @@
 
     ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
         auto* call = src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::Call>();
-        auto* ty_conv = call->Target()->As<sem::TypeConversion>();
+        auto* ty_conv = call->Target()->As<sem::ValueConversion>();
         if (!ty_conv) {
             return nullptr;
         }
diff --git a/src/tint/transform/vectorize_scalar_matrix_initializers.cc b/src/tint/transform/vectorize_scalar_matrix_initializers.cc
index 5c58280..e35cfb3 100644
--- a/src/tint/transform/vectorize_scalar_matrix_initializers.cc
+++ b/src/tint/transform/vectorize_scalar_matrix_initializers.cc
@@ -19,7 +19,7 @@
 
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
 #include "src/tint/sem/value_expression.h"
 #include "src/tint/type/abstract_numeric.h"
 #include "src/tint/utils/map.h"
@@ -32,7 +32,7 @@
 bool ShouldRun(const Program* program) {
     for (auto* node : program->ASTNodes().Objects()) {
         if (auto* call = program->Sem().Get<sem::Call>(node)) {
-            if (call->Target()->Is<sem::TypeInitializer>() && call->Type()->Is<type::Matrix>()) {
+            if (call->Target()->Is<sem::ValueConstructor>() && call->Type()->Is<type::Matrix>()) {
                 auto& args = call->Arguments();
                 if (!args.IsEmpty() && args[0]->Type()->UnwrapRef()->is_scalar()) {
                     return true;
@@ -63,7 +63,7 @@
 
     ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
         auto* call = src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::Call>();
-        auto* ty_init = call->Target()->As<sem::TypeInitializer>();
+        auto* ty_init = call->Target()->As<sem::ValueConstructor>();
         if (!ty_init) {
             return nullptr;
         }
diff --git a/src/tint/transform/vertex_pulling.cc b/src/tint/transform/vertex_pulling.cc
index 8d151bf..ecc7576 100644
--- a/src/tint/transform/vertex_pulling.cc
+++ b/src/tint/transform/vertex_pulling.cc
@@ -20,6 +20,7 @@
 #include "src/tint/ast/assignment_statement.h"
 #include "src/tint/ast/bitcast_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/utils/compiler_macros.h"
@@ -321,8 +322,9 @@
                                         });
         for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
             // The decorated variable with struct type
-            b.GlobalVar(GetVertexBufferName(i), b.ty.Of(struct_type), type::AddressSpace::kStorage,
-                        type::Access::kRead, b.Binding(AInt(i)), b.Group(AInt(cfg.pulling_group)));
+            b.GlobalVar(GetVertexBufferName(i), b.ty.Of(struct_type),
+                        builtin::AddressSpace::kStorage, builtin::Access::kRead, b.Binding(AInt(i)),
+                        b.Group(AInt(cfg.pulling_group)));
         }
     }
 
@@ -772,17 +774,18 @@
             }
             location_info[sem->Location().value()] = info;
         } else {
-            auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes);
-            if (TINT_UNLIKELY(!builtin)) {
+            auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes);
+            if (TINT_UNLIKELY(!builtin_attr)) {
                 TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
                 return;
             }
+            auto builtin = src->Sem().Get(builtin_attr)->Value();
             // Check for existing vertex_index and instance_index builtins.
-            if (builtin->builtin == builtin::BuiltinValue::kVertexIndex) {
+            if (builtin == builtin::BuiltinValue::kVertexIndex) {
                 vertex_index_expr = [this, param]() {
                     return b.Expr(ctx.Clone(param->name->symbol));
                 };
-            } else if (builtin->builtin == builtin::BuiltinValue::kInstanceIndex) {
+            } else if (builtin == builtin::BuiltinValue::kInstanceIndex) {
                 instance_index_expr = [this, param]() {
                     return b.Expr(ctx.Clone(param->name->symbol));
                 };
@@ -825,15 +828,16 @@
                 location_info[sem->Location().value()] = info;
                 has_locations = true;
             } else {
-                auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(member->attributes);
-                if (TINT_UNLIKELY(!builtin)) {
+                auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(member->attributes);
+                if (TINT_UNLIKELY(!builtin_attr)) {
                     TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
                     return;
                 }
+                auto builtin = src->Sem().Get(builtin_attr)->Value();
                 // Check for existing vertex_index and instance_index builtins.
-                if (builtin->builtin == builtin::BuiltinValue::kVertexIndex) {
+                if (builtin == builtin::BuiltinValue::kVertexIndex) {
                     vertex_index_expr = member_expr;
-                } else if (builtin->builtin == builtin::BuiltinValue::kInstanceIndex) {
+                } else if (builtin == builtin::BuiltinValue::kInstanceIndex) {
                     instance_index_expr = member_expr;
                 }
                 members_to_clone.Push(member);
diff --git a/src/tint/transform/zero_init_workgroup_memory.cc b/src/tint/transform/zero_init_workgroup_memory.cc
index 49d96d9..9040e09 100644
--- a/src/tint/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/transform/zero_init_workgroup_memory.cc
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "src/tint/ast/workgroup_attribute.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/variable.h"
@@ -36,7 +37,8 @@
 bool ShouldRun(const Program* program) {
     for (auto* global : program->AST().GlobalVariables()) {
         if (auto* var = global->As<ast::Var>()) {
-            if (var->declared_address_space == type::AddressSpace::kWorkgroup) {
+            auto* v = program->Sem().Get(var);
+            if (v->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
                 return true;
             }
         }
@@ -139,7 +141,7 @@
         // workgroup storage variables used by `fn`. This will populate #statements.
         auto* func = sem.Get(fn);
         for (auto* var : func->TransitivelyReferencedGlobals()) {
-            if (var->AddressSpace() == type::AddressSpace::kWorkgroup) {
+            if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
                 auto get_expr = [&](uint32_t num_values) {
                     auto var_name = ctx.Clone(var->Declaration()->name->symbol);
                     return Expression{b.Expr(var_name), num_values, ArrayIndices{}};
@@ -158,8 +160,9 @@
         // parameter
         std::function<const ast::Expression*()> local_index;
         for (auto* param : fn->params) {
-            if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
-                if (builtin->builtin == builtin::BuiltinValue::kLocalInvocationIndex) {
+            if (auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
+                auto builtin = sem.Get(builtin_attr)->Value();
+                if (builtin == builtin::BuiltinValue::kLocalInvocationIndex) {
                     local_index = [=] { return b.Expr(ctx.Clone(param->name->symbol)); };
                     break;
                 }
@@ -167,9 +170,10 @@
 
             if (auto* str = sem.Get(param)->Type()->As<sem::Struct>()) {
                 for (auto* member : str->Members()) {
-                    if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(
+                    if (auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(
                             member->Declaration()->attributes)) {
-                        if (builtin->builtin == builtin::BuiltinValue::kLocalInvocationIndex) {
+                        auto builtin = sem.Get(builtin_attr)->Value();
+                        if (builtin == builtin::BuiltinValue::kLocalInvocationIndex) {
                             local_index = [=] {
                                 auto* param_expr = b.Expr(ctx.Clone(param->name->symbol));
                                 auto* member_name = ctx.Clone(member->Declaration()->name);
@@ -183,10 +187,9 @@
         }
         if (!local_index) {
             // No existing local index parameter. Append one to the entry point.
-            auto* param = b.Param(b.Symbols().New("local_invocation_index"), b.ty.u32(),
-                                  utils::Vector{
-                                      b.Builtin(builtin::BuiltinValue::kLocalInvocationIndex),
-                                  });
+            auto param_name = b.Symbols().New("local_invocation_index");
+            auto* local_invocation_index = b.Builtin(builtin::BuiltinValue::kLocalInvocationIndex);
+            auto* param = b.Param(param_name, b.ty.u32(), utils::Vector{local_invocation_index});
             ctx.InsertBack(fn->params, param);
             local_index = [=] { return b.Expr(param->name->symbol); };
         }
@@ -433,9 +436,8 @@
     }
 
     /// @returns true if a variable with store type `ty` can be efficiently zeroed
-    /// by assignment of a type initializer without operands. If
-    /// CanTriviallyZero() returns false, then the type needs to be
-    /// initialized by decomposing the initialization into multiple
+    /// by assignment of a value constructor without operands. If CanTriviallyZero() returns false,
+    /// then the type needs to be initialized by decomposing the initialization into multiple
     /// sub-initializations.
     /// @param ty the type to inspect
     bool CanTriviallyZero(const type::Type* ty) {
diff --git a/src/tint/transform/zero_init_workgroup_memory_test.cc b/src/tint/transform/zero_init_workgroup_memory_test.cc
index c067f1b..fbd7538 100644
--- a/src/tint/transform/zero_init_workgroup_memory_test.cc
+++ b/src/tint/transform/zero_init_workgroup_memory_test.cc
@@ -1366,7 +1366,7 @@
 TEST_F(ZeroInitWorkgroupMemoryTest, ArrayWithOverrideCount) {
     auto* src =
         R"(override O = 123;
-type A = array<i32, O*2>;
+alias A = array<i32, O*2>;
 
 var<workgroup> W : A;
 
diff --git a/src/tint/type/address_space_bench.cc b/src/tint/type/address_space_bench.cc
deleted file mode 100644
index ecd3ccf..0000000
--- a/src/tint/type/address_space_bench.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2022 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.
-
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/type/address_space_bench.cc.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
-#include "src/tint/type/address_space.h"
-
-#include <array>
-
-#include "benchmark/benchmark.h"
-
-namespace tint::type {
-namespace {
-
-void AddressSpaceParser(::benchmark::State& state) {
-    const char* kStrings[] = {
-        "fccnctin",       "ucti3",         "functVon",      "function",      "1unction",
-        "unJtqqon",       "llun77tion",    "ppqqivtHH",     "prcv",          "bivaGe",
-        "private",        "priviive",      "8WWivate",      "pxxvate",       "pXh_cggnstant",
-        "pX_Vonstanu",    "push_consta3t", "push_constant", "push_constanE", "push_TTPnstant",
-        "puxxdh_constan", "s44orage",      "stSSraVVe",     "RtoR22e",       "storage",
-        "sFra9e",         "stoage",        "VOORRHge",      "unfoym",        "llnnrrf77rm",
-        "unif4r00",       "uniform",       "nfoom",         "zzform",        "uiiippo1",
-        "workgrouXX",     "wor55gro99nII", "wrrrkgroSSaHH", "workgroup",     "kkrHoup",
-        "jgkrouRR",       "wokroub",
-    };
-    for (auto _ : state) {
-        for (auto* str : kStrings) {
-            auto result = ParseAddressSpace(str);
-            benchmark::DoNotOptimize(result);
-        }
-    }
-}
-
-BENCHMARK(AddressSpaceParser);
-
-}  // namespace
-}  // namespace tint::type
diff --git a/src/tint/type/pointer.cc b/src/tint/type/pointer.cc
index 809d05b..17bbe1a 100644
--- a/src/tint/type/pointer.cc
+++ b/src/tint/type/pointer.cc
@@ -24,14 +24,14 @@
 
 namespace tint::type {
 
-Pointer::Pointer(const Type* subtype, type::AddressSpace address_space, type::Access access)
+Pointer::Pointer(const Type* subtype, builtin::AddressSpace address_space, builtin::Access access)
     : Base(utils::Hash(TypeInfo::Of<Pointer>().full_hashcode, address_space, subtype, access),
            type::Flags{}),
       subtype_(subtype),
       address_space_(address_space),
       access_(access) {
     TINT_ASSERT(Type, !subtype->Is<Reference>());
-    TINT_ASSERT(Type, access != type::Access::kUndefined);
+    TINT_ASSERT(Type, access != builtin::Access::kUndefined);
 }
 
 bool Pointer::Equals(const UniqueNode& other) const {
@@ -45,7 +45,7 @@
 std::string Pointer::FriendlyName(const SymbolTable& symbols) const {
     std::ostringstream out;
     out << "ptr<";
-    if (address_space_ != AddressSpace::kNone) {
+    if (address_space_ != builtin::AddressSpace::kUndefined) {
         out << address_space_ << ", ";
     }
     out << subtype_->FriendlyName(symbols) << ", " << access_;
diff --git a/src/tint/type/pointer.h b/src/tint/type/pointer.h
index 61eab76..6e73999 100644
--- a/src/tint/type/pointer.h
+++ b/src/tint/type/pointer.h
@@ -17,8 +17,8 @@
 
 #include <string>
 
-#include "src/tint/type/access.h"
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/type/type.h"
 
 namespace tint::type {
@@ -30,7 +30,7 @@
     /// @param subtype the pointee type
     /// @param address_space the address space of the pointer
     /// @param access the resolved access control of the reference
-    Pointer(const Type* subtype, type::AddressSpace address_space, type::Access access);
+    Pointer(const Type* subtype, builtin::AddressSpace address_space, builtin::Access access);
 
     /// Destructor
     ~Pointer() override;
@@ -43,10 +43,10 @@
     const Type* StoreType() const { return subtype_; }
 
     /// @returns the address space of the pointer
-    type::AddressSpace AddressSpace() const { return address_space_; }
+    builtin::AddressSpace AddressSpace() const { return address_space_; }
 
     /// @returns the access control of the reference
-    type::Access Access() const { return access_; }
+    builtin::Access Access() const { return access_; }
 
     /// @param symbols the program's symbol table
     /// @returns the name for this type that closely resembles how it would be
@@ -59,8 +59,8 @@
 
   private:
     Type const* const subtype_;
-    type::AddressSpace const address_space_;
-    type::Access const access_;
+    builtin::AddressSpace const address_space_;
+    builtin::Access const access_;
 };
 
 }  // namespace tint::type
diff --git a/src/tint/type/pointer_test.cc b/src/tint/type/pointer_test.cc
index aa8d14e..ff030cc 100644
--- a/src/tint/type/pointer_test.cc
+++ b/src/tint/type/pointer_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/type/test_helper.h"
 #include "src/tint/type/texture.h"
 
@@ -21,15 +22,20 @@
 using PointerTest = TestHelper;
 
 TEST_F(PointerTest, Creation) {
-    auto* a = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* b = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* c = create<Pointer>(create<F32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* d = create<Pointer>(create<I32>(), AddressSpace::kPrivate, type::Access::kReadWrite);
-    auto* e = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kRead);
+    auto* a = create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
+    auto* b = create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
+    auto* c = create<Pointer>(create<F32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
+    auto* d = create<Pointer>(create<I32>(), builtin::AddressSpace::kPrivate,
+                              builtin::Access::kReadWrite);
+    auto* e =
+        create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage, builtin::Access::kRead);
 
     EXPECT_TRUE(a->StoreType()->Is<I32>());
-    EXPECT_EQ(a->AddressSpace(), AddressSpace::kStorage);
-    EXPECT_EQ(a->Access(), type::Access::kReadWrite);
+    EXPECT_EQ(a->AddressSpace(), builtin::AddressSpace::kStorage);
+    EXPECT_EQ(a->Access(), builtin::Access::kReadWrite);
 
     EXPECT_EQ(a, b);
     EXPECT_NE(a, c);
@@ -38,18 +44,25 @@
 }
 
 TEST_F(PointerTest, Hash) {
-    auto* a = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* b = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
+    auto* a = create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
+    auto* b = create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
 
     EXPECT_EQ(a->unique_hash, b->unique_hash);
 }
 
 TEST_F(PointerTest, Equals) {
-    auto* a = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* b = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* c = create<Pointer>(create<F32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* d = create<Pointer>(create<I32>(), AddressSpace::kPrivate, type::Access::kReadWrite);
-    auto* e = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kRead);
+    auto* a = create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
+    auto* b = create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
+    auto* c = create<Pointer>(create<F32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
+    auto* d = create<Pointer>(create<I32>(), builtin::AddressSpace::kPrivate,
+                              builtin::Access::kReadWrite);
+    auto* e =
+        create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage, builtin::Access::kRead);
 
     EXPECT_TRUE(a->Equals(*b));
     EXPECT_FALSE(a->Equals(*c));
@@ -59,25 +72,28 @@
 }
 
 TEST_F(PointerTest, FriendlyName) {
-    auto* r = create<Pointer>(create<I32>(), AddressSpace::kNone, type::Access::kRead);
+    auto* r =
+        create<Pointer>(create<I32>(), builtin::AddressSpace::kUndefined, builtin::Access::kRead);
     EXPECT_EQ(r->FriendlyName(Symbols()), "ptr<i32, read>");
 }
 
 TEST_F(PointerTest, FriendlyNameWithAddressSpace) {
-    auto* r = create<Pointer>(create<I32>(), AddressSpace::kWorkgroup, type::Access::kRead);
+    auto* r =
+        create<Pointer>(create<I32>(), builtin::AddressSpace::kWorkgroup, builtin::Access::kRead);
     EXPECT_EQ(r->FriendlyName(Symbols()), "ptr<workgroup, i32, read>");
 }
 
 TEST_F(PointerTest, Clone) {
-    auto* a = create<Pointer>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
+    auto* a = create<Pointer>(create<I32>(), builtin::AddressSpace::kStorage,
+                              builtin::Access::kReadWrite);
 
     type::Manager mgr;
     type::CloneContext ctx{{nullptr}, {nullptr, &mgr}};
 
     auto* ptr = a->Clone(ctx);
     EXPECT_TRUE(ptr->StoreType()->Is<I32>());
-    EXPECT_EQ(ptr->AddressSpace(), AddressSpace::kStorage);
-    EXPECT_EQ(ptr->Access(), type::Access::kReadWrite);
+    EXPECT_EQ(ptr->AddressSpace(), builtin::AddressSpace::kStorage);
+    EXPECT_EQ(ptr->Access(), builtin::Access::kReadWrite);
 }
 
 }  // namespace
diff --git a/src/tint/type/reference.cc b/src/tint/type/reference.cc
index 5951f38..5db6300 100644
--- a/src/tint/type/reference.cc
+++ b/src/tint/type/reference.cc
@@ -23,14 +23,16 @@
 
 namespace tint::type {
 
-Reference::Reference(const Type* subtype, type::AddressSpace address_space, type::Access access)
+Reference::Reference(const Type* subtype,
+                     builtin::AddressSpace address_space,
+                     builtin::Access access)
     : Base(utils::Hash(TypeInfo::Of<Reference>().full_hashcode, address_space, subtype, access),
            type::Flags{}),
       subtype_(subtype),
       address_space_(address_space),
       access_(access) {
     TINT_ASSERT(Type, !subtype->Is<Reference>());
-    TINT_ASSERT(Type, access != type::Access::kUndefined);
+    TINT_ASSERT(Type, access != builtin::Access::kUndefined);
 }
 
 bool Reference::Equals(const UniqueNode& other) const {
@@ -44,7 +46,7 @@
 std::string Reference::FriendlyName(const SymbolTable& symbols) const {
     std::ostringstream out;
     out << "ref<";
-    if (address_space_ != AddressSpace::kNone) {
+    if (address_space_ != builtin::AddressSpace::kUndefined) {
         out << address_space_ << ", ";
     }
     out << subtype_->FriendlyName(symbols) << ", " << access_;
diff --git a/src/tint/type/reference.h b/src/tint/type/reference.h
index 1999880..8bc5e33 100644
--- a/src/tint/type/reference.h
+++ b/src/tint/type/reference.h
@@ -17,8 +17,8 @@
 
 #include <string>
 
-#include "src/tint/type/access.h"
-#include "src/tint/type/address_space.h"
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/type/type.h"
 
 namespace tint::type {
@@ -30,7 +30,7 @@
     /// @param subtype the pointee type
     /// @param address_space the address space of the reference
     /// @param access the resolved access control of the reference
-    Reference(const Type* subtype, type::AddressSpace address_space, type::Access access);
+    Reference(const Type* subtype, builtin::AddressSpace address_space, builtin::Access access);
 
     /// Destructor
     ~Reference() override;
@@ -43,10 +43,10 @@
     const Type* StoreType() const { return subtype_; }
 
     /// @returns the address space of the reference
-    type::AddressSpace AddressSpace() const { return address_space_; }
+    builtin::AddressSpace AddressSpace() const { return address_space_; }
 
     /// @returns the resolved access control of the reference.
-    type::Access Access() const { return access_; }
+    builtin::Access Access() const { return access_; }
 
     /// @param symbols the program's symbol table
     /// @returns the name for this type that closely resembles how it would be
@@ -59,8 +59,8 @@
 
   private:
     Type const* const subtype_;
-    type::AddressSpace const address_space_;
-    type::Access const access_;
+    builtin::AddressSpace const address_space_;
+    builtin::Access const access_;
 };
 
 }  // namespace tint::type
diff --git a/src/tint/type/reference_test.cc b/src/tint/type/reference_test.cc
index 8b3ae18..634b17a 100644
--- a/src/tint/type/reference_test.cc
+++ b/src/tint/type/reference_test.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/type/reference.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/type/test_helper.h"
 
 namespace tint::type {
@@ -21,15 +22,20 @@
 using ReferenceTest = TestHelper;
 
 TEST_F(ReferenceTest, Creation) {
-    auto* a = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* b = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* c = create<Reference>(create<F32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* d = create<Reference>(create<I32>(), AddressSpace::kPrivate, type::Access::kReadWrite);
-    auto* e = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kRead);
+    auto* a = create<Reference>(create<I32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
+    auto* b = create<Reference>(create<I32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
+    auto* c = create<Reference>(create<F32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
+    auto* d = create<Reference>(create<I32>(), builtin::AddressSpace::kPrivate,
+                                builtin::Access::kReadWrite);
+    auto* e =
+        create<Reference>(create<I32>(), builtin::AddressSpace::kStorage, builtin::Access::kRead);
 
     EXPECT_TRUE(a->StoreType()->Is<I32>());
-    EXPECT_EQ(a->AddressSpace(), AddressSpace::kStorage);
-    EXPECT_EQ(a->Access(), type::Access::kReadWrite);
+    EXPECT_EQ(a->AddressSpace(), builtin::AddressSpace::kStorage);
+    EXPECT_EQ(a->Access(), builtin::Access::kReadWrite);
 
     EXPECT_EQ(a, b);
     EXPECT_NE(a, c);
@@ -38,18 +44,25 @@
 }
 
 TEST_F(ReferenceTest, Hash) {
-    auto* a = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* b = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
+    auto* a = create<Reference>(create<I32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
+    auto* b = create<Reference>(create<I32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
 
     EXPECT_EQ(a->unique_hash, b->unique_hash);
 }
 
 TEST_F(ReferenceTest, Equals) {
-    auto* a = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* b = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* c = create<Reference>(create<F32>(), AddressSpace::kStorage, type::Access::kReadWrite);
-    auto* d = create<Reference>(create<I32>(), AddressSpace::kPrivate, type::Access::kReadWrite);
-    auto* e = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kRead);
+    auto* a = create<Reference>(create<I32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
+    auto* b = create<Reference>(create<I32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
+    auto* c = create<Reference>(create<F32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
+    auto* d = create<Reference>(create<I32>(), builtin::AddressSpace::kPrivate,
+                                builtin::Access::kReadWrite);
+    auto* e =
+        create<Reference>(create<I32>(), builtin::AddressSpace::kStorage, builtin::Access::kRead);
 
     EXPECT_TRUE(a->Equals(*b));
     EXPECT_FALSE(a->Equals(*c));
@@ -59,25 +72,28 @@
 }
 
 TEST_F(ReferenceTest, FriendlyName) {
-    auto* r = create<Reference>(create<I32>(), AddressSpace::kNone, type::Access::kRead);
+    auto* r =
+        create<Reference>(create<I32>(), builtin::AddressSpace::kUndefined, builtin::Access::kRead);
     EXPECT_EQ(r->FriendlyName(Symbols()), "ref<i32, read>");
 }
 
 TEST_F(ReferenceTest, FriendlyNameWithAddressSpace) {
-    auto* r = create<Reference>(create<I32>(), AddressSpace::kWorkgroup, type::Access::kRead);
+    auto* r =
+        create<Reference>(create<I32>(), builtin::AddressSpace::kWorkgroup, builtin::Access::kRead);
     EXPECT_EQ(r->FriendlyName(Symbols()), "ref<workgroup, i32, read>");
 }
 
 TEST_F(ReferenceTest, Clone) {
-    auto* a = create<Reference>(create<I32>(), AddressSpace::kStorage, type::Access::kReadWrite);
+    auto* a = create<Reference>(create<I32>(), builtin::AddressSpace::kStorage,
+                                builtin::Access::kReadWrite);
 
     type::Manager mgr;
     type::CloneContext ctx{{nullptr}, {nullptr, &mgr}};
 
     auto* ref = a->Clone(ctx);
     EXPECT_TRUE(ref->StoreType()->Is<I32>());
-    EXPECT_EQ(ref->AddressSpace(), AddressSpace::kStorage);
-    EXPECT_EQ(ref->Access(), type::Access::kReadWrite);
+    EXPECT_EQ(ref->AddressSpace(), builtin::AddressSpace::kStorage);
+    EXPECT_EQ(ref->Access(), builtin::Access::kReadWrite);
 }
 
 }  // namespace
diff --git a/src/tint/type/storage_texture.cc b/src/tint/type/storage_texture.cc
index 25beb74..beb5da6 100644
--- a/src/tint/type/storage_texture.cc
+++ b/src/tint/type/storage_texture.cc
@@ -25,8 +25,8 @@
 namespace tint::type {
 
 StorageTexture::StorageTexture(TextureDimension dim,
-                               type::TexelFormat format,
-                               type::Access access,
+                               builtin::TexelFormat format,
+                               builtin::Access access,
                                Type* subtype)
     : Base(utils::Hash(TypeInfo::Of<StorageTexture>().full_hashcode, dim, format, access), dim),
       texel_format_(format),
@@ -48,35 +48,35 @@
     return out.str();
 }
 
-Type* StorageTexture::SubtypeFor(type::TexelFormat format, Manager& type_mgr) {
+Type* StorageTexture::SubtypeFor(builtin::TexelFormat format, Manager& type_mgr) {
     switch (format) {
-        case type::TexelFormat::kR32Uint:
-        case type::TexelFormat::kRgba8Uint:
-        case type::TexelFormat::kRg32Uint:
-        case type::TexelFormat::kRgba16Uint:
-        case type::TexelFormat::kRgba32Uint: {
+        case builtin::TexelFormat::kR32Uint:
+        case builtin::TexelFormat::kRgba8Uint:
+        case builtin::TexelFormat::kRg32Uint:
+        case builtin::TexelFormat::kRgba16Uint:
+        case builtin::TexelFormat::kRgba32Uint: {
             return type_mgr.Get<U32>();
         }
 
-        case type::TexelFormat::kR32Sint:
-        case type::TexelFormat::kRgba8Sint:
-        case type::TexelFormat::kRg32Sint:
-        case type::TexelFormat::kRgba16Sint:
-        case type::TexelFormat::kRgba32Sint: {
+        case builtin::TexelFormat::kR32Sint:
+        case builtin::TexelFormat::kRgba8Sint:
+        case builtin::TexelFormat::kRg32Sint:
+        case builtin::TexelFormat::kRgba16Sint:
+        case builtin::TexelFormat::kRgba32Sint: {
             return type_mgr.Get<I32>();
         }
 
-        case type::TexelFormat::kBgra8Unorm:
-        case type::TexelFormat::kRgba8Unorm:
-        case type::TexelFormat::kRgba8Snorm:
-        case type::TexelFormat::kR32Float:
-        case type::TexelFormat::kRg32Float:
-        case type::TexelFormat::kRgba16Float:
-        case type::TexelFormat::kRgba32Float: {
+        case builtin::TexelFormat::kBgra8Unorm:
+        case builtin::TexelFormat::kRgba8Unorm:
+        case builtin::TexelFormat::kRgba8Snorm:
+        case builtin::TexelFormat::kR32Float:
+        case builtin::TexelFormat::kRg32Float:
+        case builtin::TexelFormat::kRgba16Float:
+        case builtin::TexelFormat::kRgba32Float: {
             return type_mgr.Get<F32>();
         }
 
-        case type::TexelFormat::kUndefined:
+        case builtin::TexelFormat::kUndefined:
             break;
     }
 
diff --git a/src/tint/type/storage_texture.h b/src/tint/type/storage_texture.h
index 6e96907..de1b6de 100644
--- a/src/tint/type/storage_texture.h
+++ b/src/tint/type/storage_texture.h
@@ -17,8 +17,8 @@
 
 #include <string>
 
-#include "src/tint/type/access.h"
-#include "src/tint/type/texel_format.h"
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/type/texture.h"
 #include "src/tint/type/texture_dimension.h"
 
@@ -38,8 +38,8 @@
     /// @param access the access control type of the texture
     /// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
     StorageTexture(TextureDimension dim,
-                   type::TexelFormat format,
-                   type::Access access,
+                   builtin::TexelFormat format,
+                   builtin::Access access,
                    Type* subtype);
 
     /// Destructor
@@ -53,10 +53,10 @@
     Type* type() const { return subtype_; }
 
     /// @returns the texel format
-    type::TexelFormat texel_format() const { return texel_format_; }
+    builtin::TexelFormat texel_format() const { return texel_format_; }
 
     /// @returns the access control
-    type::Access access() const { return access_; }
+    builtin::Access access() const { return access_; }
 
     /// @param symbols the program's symbol table
     /// @returns the name for this type that closely resembles how it would be
@@ -66,15 +66,15 @@
     /// @param format the storage texture image format
     /// @param type_mgr the Manager used to build the returned type
     /// @returns the storage texture subtype for the given TexelFormat
-    static Type* SubtypeFor(type::TexelFormat format, Manager& type_mgr);
+    static Type* SubtypeFor(builtin::TexelFormat format, Manager& type_mgr);
 
     /// @param ctx the clone context
     /// @returns a clone of this type
     StorageTexture* Clone(CloneContext& ctx) const override;
 
   private:
-    type::TexelFormat const texel_format_;
-    type::Access const access_;
+    builtin::TexelFormat const texel_format_;
+    builtin::Access const access_;
     Type* const subtype_;
 };
 
diff --git a/src/tint/type/storage_texture_test.cc b/src/tint/type/storage_texture_test.cc
index 2ffc0b7..8e0174e 100644
--- a/src/tint/type/storage_texture_test.cc
+++ b/src/tint/type/storage_texture_test.cc
@@ -24,22 +24,25 @@
 namespace {
 
 struct StorageTextureTest : public TestHelper {
-    StorageTexture* Create(TextureDimension dims, type::TexelFormat fmt, type::Access access) {
+    StorageTexture* Create(TextureDimension dims,
+                           builtin::TexelFormat fmt,
+                           builtin::Access access) {
         auto* subtype = StorageTexture::SubtypeFor(fmt, Types());
         return create<StorageTexture>(dims, fmt, access, subtype);
     }
 };
 
 TEST_F(StorageTextureTest, Creation) {
-    auto* a =
-        Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
-    auto* b =
-        Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
-    auto* c =
-        Create(TextureDimension::k2d, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
-    auto* d =
-        Create(TextureDimension::kCube, type::TexelFormat::kR32Float, type::Access::kReadWrite);
-    auto* e = Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kRead);
+    auto* a = Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
+    auto* b = Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
+    auto* c = Create(TextureDimension::k2d, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
+    auto* d = Create(TextureDimension::kCube, builtin::TexelFormat::kR32Float,
+                     builtin::Access::kReadWrite);
+    auto* e =
+        Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float, builtin::Access::kRead);
 
     EXPECT_TRUE(a->type()->Is<F32>());
     EXPECT_EQ(a->dim(), TextureDimension::kCube);
@@ -51,24 +54,25 @@
 }
 
 TEST_F(StorageTextureTest, Hash) {
-    auto* a =
-        Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
-    auto* b =
-        Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
+    auto* a = Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
+    auto* b = Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
 
     EXPECT_EQ(a->unique_hash, b->unique_hash);
 }
 
 TEST_F(StorageTextureTest, Equals) {
-    auto* a =
-        Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
-    auto* b =
-        Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
-    auto* c =
-        Create(TextureDimension::k2d, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
-    auto* d =
-        Create(TextureDimension::kCube, type::TexelFormat::kR32Float, type::Access::kReadWrite);
-    auto* e = Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kRead);
+    auto* a = Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
+    auto* b = Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
+    auto* c = Create(TextureDimension::k2d, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
+    auto* d = Create(TextureDimension::kCube, builtin::TexelFormat::kR32Float,
+                     builtin::Access::kReadWrite);
+    auto* e =
+        Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float, builtin::Access::kRead);
 
     EXPECT_TRUE(a->Equals(*b));
     EXPECT_FALSE(a->Equals(*c));
@@ -78,26 +82,26 @@
 }
 
 TEST_F(StorageTextureTest, Dim) {
-    auto* s = Create(TextureDimension::k2dArray, type::TexelFormat::kRgba32Float,
-                     type::Access::kReadWrite);
+    auto* s = Create(TextureDimension::k2dArray, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
     EXPECT_EQ(s->dim(), TextureDimension::k2dArray);
 }
 
 TEST_F(StorageTextureTest, Format) {
-    auto* s = Create(TextureDimension::k2dArray, type::TexelFormat::kRgba32Float,
-                     type::Access::kReadWrite);
-    EXPECT_EQ(s->texel_format(), type::TexelFormat::kRgba32Float);
+    auto* s = Create(TextureDimension::k2dArray, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
+    EXPECT_EQ(s->texel_format(), builtin::TexelFormat::kRgba32Float);
 }
 
 TEST_F(StorageTextureTest, FriendlyName) {
-    auto* s = Create(TextureDimension::k2dArray, type::TexelFormat::kRgba32Float,
-                     type::Access::kReadWrite);
+    auto* s = Create(TextureDimension::k2dArray, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
     EXPECT_EQ(s->FriendlyName(Symbols()), "texture_storage_2d_array<rgba32float, read_write>");
 }
 
 TEST_F(StorageTextureTest, F32) {
-    auto* s = Create(TextureDimension::k2dArray, type::TexelFormat::kRgba32Float,
-                     type::Access::kReadWrite);
+    auto* s = Create(TextureDimension::k2dArray, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
 
     auto program = Build();
 
@@ -108,9 +112,9 @@
 }
 
 TEST_F(StorageTextureTest, U32) {
-    auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRg32Uint, Types());
-    auto* s = create<StorageTexture>(TextureDimension::k2dArray, type::TexelFormat::kRg32Uint,
-                                     type::Access::kReadWrite, subtype);
+    auto* subtype = StorageTexture::SubtypeFor(builtin::TexelFormat::kRg32Uint, Types());
+    auto* s = create<StorageTexture>(TextureDimension::k2dArray, builtin::TexelFormat::kRg32Uint,
+                                     builtin::Access::kReadWrite, subtype);
 
     auto program = Build();
 
@@ -121,9 +125,9 @@
 }
 
 TEST_F(StorageTextureTest, I32) {
-    auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Sint, Types());
-    auto* s = create<StorageTexture>(TextureDimension::k2dArray, type::TexelFormat::kRgba32Sint,
-                                     type::Access::kReadWrite, subtype);
+    auto* subtype = StorageTexture::SubtypeFor(builtin::TexelFormat::kRgba32Sint, Types());
+    auto* s = create<StorageTexture>(TextureDimension::k2dArray, builtin::TexelFormat::kRgba32Sint,
+                                     builtin::Access::kReadWrite, subtype);
 
     auto program = Build();
 
@@ -134,15 +138,15 @@
 }
 
 TEST_F(StorageTextureTest, Clone) {
-    auto* a =
-        Create(TextureDimension::kCube, type::TexelFormat::kRgba32Float, type::Access::kReadWrite);
+    auto* a = Create(TextureDimension::kCube, builtin::TexelFormat::kRgba32Float,
+                     builtin::Access::kReadWrite);
 
     type::Manager mgr;
     type::CloneContext ctx{{nullptr}, {nullptr, &mgr}};
 
     auto* mt = a->Clone(ctx);
     EXPECT_EQ(mt->dim(), TextureDimension::kCube);
-    EXPECT_EQ(mt->texel_format(), type::TexelFormat::kRgba32Float);
+    EXPECT_EQ(mt->texel_format(), builtin::TexelFormat::kRgba32Float);
     EXPECT_TRUE(mt->type()->Is<F32>());
 }
 
diff --git a/src/tint/type/struct.h b/src/tint/type/struct.h
index e80dcc1..0130111 100644
--- a/src/tint/type/struct.h
+++ b/src/tint/type/struct.h
@@ -21,8 +21,8 @@
 #include <string>
 #include <unordered_set>
 
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/symbol.h"
-#include "src/tint/type/address_space.h"
 #include "src/tint/type/node.h"
 #include "src/tint/type/type.h"
 #include "src/tint/utils/vector.h"
@@ -100,22 +100,22 @@
 
     /// Adds the AddressSpace usage to the structure.
     /// @param usage the storage usage
-    void AddUsage(AddressSpace usage) { address_space_usage_.emplace(usage); }
+    void AddUsage(builtin::AddressSpace usage) { address_space_usage_.emplace(usage); }
 
     /// @returns the set of address space uses of this structure
-    const std::unordered_set<AddressSpace>& AddressSpaceUsage() const {
+    const std::unordered_set<builtin::AddressSpace>& AddressSpaceUsage() const {
         return address_space_usage_;
     }
 
     /// @param usage the AddressSpace usage type to query
     /// @returns true iff this structure has been used as the given address space
-    bool UsedAs(AddressSpace usage) const { return address_space_usage_.count(usage) > 0; }
+    bool UsedAs(builtin::AddressSpace usage) const { return address_space_usage_.count(usage) > 0; }
 
     /// @returns true iff this structure has been used by address space that's
     /// host-shareable.
     bool IsHostShareable() const {
         for (auto sc : address_space_usage_) {
-            if (type::IsHostShareable(sc)) {
+            if (builtin::IsHostShareable(sc)) {
                 return true;
             }
         }
@@ -160,7 +160,7 @@
     const uint32_t align_;
     const uint32_t size_;
     const uint32_t size_no_padding_;
-    std::unordered_set<AddressSpace> address_space_usage_;
+    std::unordered_set<builtin::AddressSpace> address_space_usage_;
     std::unordered_set<PipelineStageUsage> pipeline_stage_uses_;
     utils::Vector<const Struct*, 2> concrete_types_;
 };
diff --git a/src/tint/type/type_test.cc b/src/tint/type/type_test.cc
index 62ec706..1565e10 100644
--- a/src/tint/type/type_test.cc
+++ b/src/tint/type/type_test.cc
@@ -44,7 +44,7 @@
     const Matrix* mat4x3_f16 = create<Matrix>(vec3_f16, 4u);
     const Matrix* mat4x3_af = create<Matrix>(vec3_af, 4u);
     const Reference* ref_u32 =
-        create<Reference>(u32, AddressSpace::kPrivate, type::Access::kReadWrite);
+        create<Reference>(u32, builtin::AddressSpace::kPrivate, builtin::Access::kReadWrite);
     const Struct* str_f32 = create<Struct>(Source{},
                                            Sym("str_f32"),
                                            utils::Vector{
diff --git a/src/tint/utils/block_allocator.h b/src/tint/utils/block_allocator.h
index e75a0c6..b1465cb 100644
--- a/src/tint/utils/block_allocator.h
+++ b/src/tint/utils/block_allocator.h
@@ -210,7 +210,7 @@
 
     /// Creates a new `TYPE` owned by the BlockAllocator.
     /// When the BlockAllocator is destructed the object will be destructed and freed.
-    /// @param args the arguments to pass to the type constructor
+    /// @param args the arguments to pass to the constructor
     /// @returns the pointer to the constructed object
     template <typename TYPE = T, typename... ARGS>
     TYPE* Create(ARGS&&... args) {
diff --git a/src/tint/utils/enum_set.h b/src/tint/utils/enum_set.h
index 19d1a82..9b75ba0 100644
--- a/src/tint/utils/enum_set.h
+++ b/src/tint/utils/enum_set.h
@@ -192,14 +192,14 @@
     };
 
     /// @returns an read-only iterator to the beginning of the set
-    Iterator begin() {
+    Iterator begin() const {
         auto it = Iterator{set, -1};
         ++it;  // Move to first set bit
         return it;
     }
 
     /// @returns an iterator to the beginning of the set
-    Iterator end() { return Iterator{set, Iterator::kEnd}; }
+    Iterator end() const { return Iterator{set, Iterator::kEnd}; }
 
   private:
     static constexpr uint64_t Bit(Enum value) {
diff --git a/src/tint/utils/slice.h b/src/tint/utils/slice.h
new file mode 100644
index 0000000..719a53e
--- /dev/null
+++ b/src/tint/utils/slice.h
@@ -0,0 +1,205 @@
+// Copyright 2023 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_TINT_UTILS_SLICE_H_
+#define SRC_TINT_UTILS_SLICE_H_
+
+#include <cstdint>
+#include <iterator>
+
+#include "src/tint/castable.h"
+#include "src/tint/traits.h"
+
+namespace tint::utils {
+
+/// A type used to indicate an empty array.
+struct EmptyType {};
+
+/// An instance of the EmptyType.
+static constexpr EmptyType Empty;
+
+/// Mode enumerator for ReinterpretSlice
+enum class ReinterpretMode {
+    /// Only upcasts of pointers are permitted
+    kSafe,
+    /// Potentially unsafe downcasts of pointers are also permitted
+    kUnsafe,
+};
+
+namespace detail {
+
+template <typename TO, typename FROM>
+static constexpr bool ConstRemoved = std::is_const_v<FROM> && !std::is_const_v<TO>;
+
+/// Private implementation of tint::utils::CanReinterpretSlice.
+/// Specialized for the case of TO equal to FROM, which is the common case, and avoids inspection of
+/// the base classes, which can be troublesome if the slice is of an incomplete type.
+template <ReinterpretMode MODE, typename TO, typename FROM>
+struct CanReinterpretSlice {
+  private:
+    using TO_EL = std::remove_pointer_t<std::decay_t<TO>>;
+    using FROM_EL = std::remove_pointer_t<std::decay_t<FROM>>;
+
+  public:
+    /// @see utils::CanReinterpretSlice
+    static constexpr bool value =
+        // const can only be applied, not removed
+        !ConstRemoved<TO, FROM> &&
+
+        // Both TO and FROM are the same type (ignoring const)
+        (std::is_same_v<std::remove_const_t<TO>, std::remove_const_t<FROM>> ||
+
+         // Both TO and FROM are pointers...
+         ((std::is_pointer_v<TO> && std::is_pointer_v<FROM>)&&
+
+          // const can only be applied to element type, not removed
+          !ConstRemoved<TO_EL, FROM_EL> &&
+
+          // Either:
+          // * Both the pointer elements are of the same type (ignoring const)
+          // * Both the pointer elements are both Castable, and MODE is kUnsafe, or FROM is of,
+          // or
+          //   derives from TO
+          (std::is_same_v<std::remove_const_t<FROM_EL>, std::remove_const_t<TO_EL>> ||
+           (IsCastable<FROM_EL, TO_EL> &&
+            (MODE == ReinterpretMode::kUnsafe || traits::IsTypeOrDerived<FROM_EL, TO_EL>)))));
+};
+
+/// Specialization of 'CanReinterpretSlice' for when TO and FROM are equal types.
+template <typename T, ReinterpretMode MODE>
+struct CanReinterpretSlice<MODE, T, T> {
+    /// Always `true` as TO and FROM are the same type.
+    static constexpr bool value = true;
+};
+
+}  // namespace detail
+
+/// Evaluates whether a `Slice<FROM>` and be reinterpreted as a `Slice<TO>`.
+/// Slices can be reinterpreted if:
+///  * TO has the same or more 'constness' than FROM.
+///  * And either:
+///  * `FROM` and `TO` are pointers to the same type
+///  * `FROM` and `TO` are pointers to CastableBase (or derived), and the pointee type of `TO` is of
+///     the same type as, or is an ancestor of the pointee type of `FROM`.
+template <ReinterpretMode MODE, typename TO, typename FROM>
+static constexpr bool CanReinterpretSlice = detail::CanReinterpretSlice<MODE, TO, FROM>::value;
+
+/// A slice represents a contigious array of elements of type T.
+template <typename T>
+struct Slice {
+    /// Type of `T`.
+    using value_type = T;
+
+    /// The pointer to the first element in the slice
+    T* data = nullptr;
+
+    /// The total number of elements in the slice
+    size_t len = 0;
+
+    /// The total capacity of the backing store for the slice
+    size_t cap = 0;
+
+    /// Constructor
+    Slice() = default;
+
+    /// Constructor
+    Slice(EmptyType) {}  // NOLINT
+
+    /// Constructor
+    /// @param d pointer to the first element in the slice
+    /// @param l total number of elements in the slice
+    /// @param c total capacity of the backing store for the slice
+    Slice(T* d, size_t l, size_t c) : data(d), len(l), cap(c) {}
+
+    /// Constructor
+    /// @param elements c-array of elements
+    template <size_t N>
+    Slice(T (&elements)[N])  // NOLINT
+        : data(elements), len(N), cap(N) {}
+
+    /// Reinterprets this slice as `const Slice<TO>&`
+    /// @returns the reinterpreted slice
+    /// @see CanReinterpretSlice
+    template <typename TO, ReinterpretMode MODE = ReinterpretMode::kSafe>
+    const Slice<TO>& Reinterpret() const {
+        static_assert(CanReinterpretSlice<MODE, TO, T>);
+        return *Bitcast<const Slice<TO>*>(this);
+    }
+
+    /// Reinterprets this slice as `Slice<TO>&`
+    /// @returns the reinterpreted slice
+    /// @see CanReinterpretSlice
+    template <typename TO, ReinterpretMode MODE = ReinterpretMode::kSafe>
+    Slice<TO>& Reinterpret() {
+        static_assert(CanReinterpretSlice<MODE, TO, T>);
+        return *Bitcast<Slice<TO>*>(this);
+    }
+
+    /// @return true if the slice length is zero
+    bool IsEmpty() const { return len == 0; }
+
+    /// Index operator
+    /// @param i the element index. Must be less than `len`.
+    /// @returns a reference to the i'th element.
+    T& operator[](size_t i) { return data[i]; }
+
+    /// Index operator
+    /// @param i the element index. Must be less than `len`.
+    /// @returns a reference to the i'th element.
+    const T& operator[](size_t i) const { return data[i]; }
+
+    /// @returns a reference to the first element in the vector
+    T& Front() { return data[0]; }
+
+    /// @returns a reference to the first element in the vector
+    const T& Front() const { return data[0]; }
+
+    /// @returns a reference to the last element in the vector
+    T& Back() { return data[len - 1]; }
+
+    /// @returns a reference to the last element in the vector
+    const T& Back() const { return data[len - 1]; }
+
+    /// @returns a pointer to the first element in the vector
+    T* begin() { return data; }
+
+    /// @returns a pointer to the first element in the vector
+    const T* begin() const { return data; }
+
+    /// @returns a pointer to one past the last element in the vector
+    T* end() { return data + len; }
+
+    /// @returns a pointer to one past the last element in the vector
+    const T* end() const { return data + len; }
+
+    /// @returns a reverse iterator starting with the last element in the vector
+    auto rbegin() { return std::reverse_iterator<T*>(end()); }
+
+    /// @returns a reverse iterator starting with the last element in the vector
+    auto rbegin() const { return std::reverse_iterator<const T*>(end()); }
+
+    /// @returns the end for a reverse iterator
+    auto rend() { return std::reverse_iterator<T*>(begin()); }
+
+    /// @returns the end for a reverse iterator
+    auto rend() const { return std::reverse_iterator<const T*>(begin()); }
+};
+
+/// Deduction guide for Slice from c-array
+template <typename T, size_t N>
+Slice(T (&elements)[N]) -> Slice<T>;
+
+}  // namespace tint::utils
+
+#endif  // SRC_TINT_UTILS_SLICE_H_
diff --git a/src/tint/utils/slice_test.cc b/src/tint/utils/slice_test.cc
new file mode 100644
index 0000000..6a4493c
--- /dev/null
+++ b/src/tint/utils/slice_test.cc
@@ -0,0 +1,131 @@
+// Copyright 2023 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/tint/utils/slice.h"
+
+#include "gmock/gmock.h"
+
+namespace tint::utils {
+namespace {
+
+class C0 : public Castable<C0> {};
+class C1 : public Castable<C1, C0> {};
+class C2a : public Castable<C2a, C1> {};
+class C2b : public Castable<C2b, C1> {};
+
+////////////////////////////////////////////////////////////////////////////////
+// Static asserts
+////////////////////////////////////////////////////////////////////////////////
+// Non-pointer
+static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, int, int>, "same type");
+static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, int const, int>, "apply const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, int, int const>, "remove const");
+
+// Non-castable pointers
+static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, int* const, int*>, "apply ptr const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, int*, int* const>, "remove ptr const");
+static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, int const*, int*>, "apply el const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, int*, int const*>, "remove el const");
+
+// Castable
+static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, const C0*, C0*>, "apply const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C0*, const C0*>, "remove const");
+static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, C0*, C1*>, "up cast");
+static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, const C0*, const C1*>, "up cast");
+static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, const C0*, C1*>, "up cast, apply const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C0*, const C1*>,
+              "up cast, remove const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C1*, C0*>, "down cast");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C1*, const C0*>, "down cast");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C1*, C0*>,
+              "down cast, apply const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C1*, const C0*>,
+              "down cast, remove const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C1*, C0*>,
+              "down cast, apply const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C1*, const C0*>,
+              "down cast, remove const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C2a*, C2b*>, "sideways cast");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C2a*, const C2b*>,
+              "sideways cast");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C2a*, C2b*>,
+              "sideways cast, apply const");
+static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C2a*, const C2b*>,
+              "sideways cast, remove const");
+
+TEST(TintSliceTest, Ctor) {
+    Slice<int> slice;
+    EXPECT_EQ(slice.data, nullptr);
+    EXPECT_EQ(slice.len, 0u);
+    EXPECT_EQ(slice.cap, 0u);
+    EXPECT_TRUE(slice.IsEmpty());
+}
+
+TEST(TintSliceTest, CtorEmpty) {
+    Slice<int> slice{Empty};
+    EXPECT_EQ(slice.data, nullptr);
+    EXPECT_EQ(slice.len, 0u);
+    EXPECT_EQ(slice.cap, 0u);
+    EXPECT_TRUE(slice.IsEmpty());
+}
+
+TEST(TintSliceTest, CtorCArray) {
+    int elements[] = {1, 2, 3};
+
+    auto slice = Slice{elements};
+    EXPECT_EQ(slice.data, elements);
+    EXPECT_EQ(slice.len, 3u);
+    EXPECT_EQ(slice.cap, 3u);
+    EXPECT_FALSE(slice.IsEmpty());
+}
+
+TEST(TintSliceTest, Index) {
+    int elements[] = {1, 2, 3};
+
+    auto slice = Slice{elements};
+    EXPECT_EQ(slice[0], 1);
+    EXPECT_EQ(slice[1], 2);
+    EXPECT_EQ(slice[2], 3);
+}
+
+TEST(TintSliceTest, Front) {
+    int elements[] = {1, 2, 3};
+    auto slice = Slice{elements};
+    EXPECT_EQ(slice.Front(), 1);
+}
+
+TEST(TintSliceTest, Back) {
+    int elements[] = {1, 2, 3};
+    auto slice = Slice{elements};
+    EXPECT_EQ(slice.Back(), 3);
+}
+
+TEST(TintSliceTest, BeginEnd) {
+    int elements[] = {1, 2, 3};
+    auto slice = Slice{elements};
+    EXPECT_THAT(slice, testing::ElementsAre(1, 2, 3));
+}
+
+TEST(TintSliceTest, ReverseBeginEnd) {
+    int elements[] = {1, 2, 3};
+    auto slice = Slice{elements};
+    size_t i = 0;
+    for (auto it = slice.rbegin(); it != slice.rend(); it++) {
+        EXPECT_EQ(*it, elements[2 - i]);
+        i++;
+    }
+}
+
+}  // namespace
+}  // namespace tint::utils
diff --git a/src/tint/utils/string.cc b/src/tint/utils/string.cc
index 354ad96..bccd52c 100644
--- a/src/tint/utils/string.cc
+++ b/src/tint/utils/string.cc
@@ -48,4 +48,36 @@
     return at(len_a, len_b);
 }
 
+void SuggestAlternatives(std::string_view got,
+                         Slice<char const* const> strings,
+                         std::ostringstream& ss) {
+    // If the string typed was within kSuggestionDistance of one of the possible enum values,
+    // suggest that. Don't bother with suggestions if the string was extremely long.
+    constexpr size_t kSuggestionDistance = 5;
+    constexpr size_t kSuggestionMaxLength = 64;
+    if (!got.empty() && got.size() < kSuggestionMaxLength) {
+        size_t candidate_dist = kSuggestionDistance;
+        const char* candidate = nullptr;
+        for (auto* str : strings) {
+            auto dist = utils::Distance(str, got);
+            if (dist < candidate_dist) {
+                candidate = str;
+                candidate_dist = dist;
+            }
+        }
+        if (candidate) {
+            ss << "Did you mean '" << candidate << "'?\n";
+        }
+    }
+
+    // List all the possible enumerator values
+    ss << "Possible values: ";
+    for (auto* str : strings) {
+        if (str != strings[0]) {
+            ss << ", ";
+        }
+        ss << "'" << str << "'";
+    }
+}
+
 }  // namespace tint::utils
diff --git a/src/tint/utils/string.h b/src/tint/utils/string.h
index 5c05ebf..08e0be3 100644
--- a/src/tint/utils/string.h
+++ b/src/tint/utils/string.h
@@ -19,6 +19,8 @@
 #include <string>
 #include <variant>
 
+#include "src/tint/utils/slice.h"
+
 namespace tint::utils {
 
 /// @param str the string to apply replacements to
@@ -66,42 +68,13 @@
 /// @returns the Levenshtein distance between @p a and @p b
 size_t Distance(std::string_view a, std::string_view b);
 
-/// Suggest alternatives for an unrecognized string from a list of expected values.
+/// Suggest alternatives for an unrecognized string from a list of possible values.
 /// @param got the unrecognized string
-/// @param strings the list of expected values
+/// @param strings the list of possible values
 /// @param ss the stream to write the suggest and list of possible values to
-template <size_t N>
 void SuggestAlternatives(std::string_view got,
-                         const char* const (&strings)[N],
-                         std::ostringstream& ss) {
-    // If the string typed was within kSuggestionDistance of one of the possible enum values,
-    // suggest that. Don't bother with suggestions if the string was extremely long.
-    constexpr size_t kSuggestionDistance = 5;
-    constexpr size_t kSuggestionMaxLength = 64;
-    if (!got.empty() && got.size() < kSuggestionMaxLength) {
-        size_t candidate_dist = kSuggestionDistance;
-        const char* candidate = nullptr;
-        for (auto* str : strings) {
-            auto dist = utils::Distance(str, got);
-            if (dist < candidate_dist) {
-                candidate = str;
-                candidate_dist = dist;
-            }
-        }
-        if (candidate) {
-            ss << "Did you mean '" << candidate << "'?\n";
-        }
-    }
-
-    // List all the possible enumerator values
-    ss << "Possible values: ";
-    for (auto* str : strings) {
-        if (str != strings[0]) {
-            ss << ", ";
-        }
-        ss << "'" << str << "'";
-    }
-}
+                         Slice<char const* const> strings,
+                         std::ostringstream& ss);
 
 }  // namespace tint::utils
 
diff --git a/src/tint/utils/string_test.cc b/src/tint/utils/string_test.cc
index 6b17dfb..b9e1ebb 100644
--- a/src/tint/utils/string_test.cc
+++ b/src/tint/utils/string_test.cc
@@ -60,14 +60,16 @@
 
 TEST(StringTest, SuggestAlternatives) {
     {
+        const char* alternatives[] = {"hello world", "Hello World"};
         std::ostringstream ss;
-        SuggestAlternatives("hello wordl", {"hello world", "Hello World"}, ss);
+        SuggestAlternatives("hello wordl", alternatives, ss);
         EXPECT_EQ(ss.str(), R"(Did you mean 'hello world'?
 Possible values: 'hello world', 'Hello World')");
     }
     {
+        const char* alternatives[] = {"foobar", "something else"};
         std::ostringstream ss;
-        SuggestAlternatives("hello world", {"foobar", "something else"}, ss);
+        SuggestAlternatives("hello world", alternatives, ss);
         EXPECT_EQ(ss.str(), R"(Possible values: 'foobar', 'something else')");
     }
 }
diff --git a/src/tint/utils/vector.h b/src/tint/utils/vector.h
index cca2409..e39854a 100644
--- a/src/tint/utils/vector.h
+++ b/src/tint/utils/vector.h
@@ -19,14 +19,14 @@
 #include <stdint.h>
 #include <algorithm>
 #include <iterator>
+#include <new>
 #include <ostream>
 #include <utility>
 #include <vector>
 
-#include "src/tint/castable.h"
-#include "src/tint/traits.h"
 #include "src/tint/utils/bitcast.h"
 #include "src/tint/utils/compiler_macros.h"
+#include "src/tint/utils/slice.h"
 #include "src/tint/utils/string.h"
 
 namespace tint::utils {
@@ -41,137 +41,6 @@
 
 namespace tint::utils {
 
-/// A type used to indicate an empty array.
-struct EmptyType {};
-
-/// An instance of the EmptyType.
-static constexpr EmptyType Empty;
-
-/// A slice represents a contigious array of elements of type T.
-template <typename T>
-struct Slice {
-    /// The pointer to the first element in the slice
-    T* data = nullptr;
-
-    /// The total number of elements in the slice
-    size_t len = 0;
-
-    /// The total capacity of the backing store for the slice
-    size_t cap = 0;
-
-    /// Index operator
-    /// @param i the element index. Must be less than `len`.
-    /// @returns a reference to the i'th element.
-    T& operator[](size_t i) { return data[i]; }
-
-    /// Index operator
-    /// @param i the element index. Must be less than `len`.
-    /// @returns a reference to the i'th element.
-    const T& operator[](size_t i) const { return data[i]; }
-
-    /// @returns a reference to the first element in the vector
-    T& Front() { return data[0]; }
-
-    /// @returns a reference to the first element in the vector
-    const T& Front() const { return data[0]; }
-
-    /// @returns a reference to the last element in the vector
-    T& Back() { return data[len - 1]; }
-
-    /// @returns a reference to the last element in the vector
-    const T& Back() const { return data[len - 1]; }
-
-    /// @returns a pointer to the first element in the vector
-    T* begin() { return data; }
-
-    /// @returns a pointer to the first element in the vector
-    const T* begin() const { return data; }
-
-    /// @returns a pointer to one past the last element in the vector
-    T* end() { return data + len; }
-
-    /// @returns a pointer to one past the last element in the vector
-    const T* end() const { return data + len; }
-
-    /// @returns a reverse iterator starting with the last element in the vector
-    auto rbegin() { return std::reverse_iterator<T*>(end()); }
-
-    /// @returns a reverse iterator starting with the last element in the vector
-    auto rbegin() const { return std::reverse_iterator<const T*>(end()); }
-
-    /// @returns the end for a reverse iterator
-    auto rend() { return std::reverse_iterator<T*>(begin()); }
-
-    /// @returns the end for a reverse iterator
-    auto rend() const { return std::reverse_iterator<const T*>(begin()); }
-};
-
-/// Mode enumerator for ReinterpretSlice
-enum class ReinterpretMode {
-    /// Only upcasts of pointers are permitted
-    kSafe,
-    /// Potentially unsafe downcasts of pointers are also permitted
-    kUnsafe,
-};
-
-namespace detail {
-
-/// Private implementation of tint::utils::CanReinterpretSlice.
-/// Specialized for the case of TO equal to FROM, which is the common case, and avoids inspection of
-/// the base classes, which can be troublesome if the slice is of an incomplete type.
-template <ReinterpretMode MODE, typename TO, typename FROM>
-struct CanReinterpretSlice {
-    /// True if a slice of FROM can be reinterpreted as a slice of TO
-    static constexpr bool value =
-        // Both TO and FROM are pointers
-        (std::is_pointer_v<TO> && std::is_pointer_v<FROM>)&&  //
-        // const can only be applied, not removed
-        (std::is_const_v<std::remove_pointer_t<TO>> ||
-         !std::is_const_v<std::remove_pointer_t<FROM>>)&&  //
-        // TO and FROM are both Castable
-        IsCastable<std::remove_pointer_t<FROM>, std::remove_pointer_t<TO>> &&  //
-        // MODE is kUnsafe, or FROM is of, or derives from TO
-        (MODE == ReinterpretMode::kUnsafe ||
-         traits::IsTypeOrDerived<std::remove_pointer_t<FROM>, std::remove_pointer_t<TO>>);
-};
-
-/// Specialization of 'CanReinterpretSlice' for when TO and FROM are equal types.
-template <typename T, ReinterpretMode MODE>
-struct CanReinterpretSlice<MODE, T, T> {
-    /// Always `true` as TO and FROM are the same type.
-    static constexpr bool value = true;
-};
-
-}  // namespace detail
-
-/// Evaluates whether a `vector<FROM>` and be reinterpreted as a `vector<TO>`.
-/// Vectors can be reinterpreted if both `FROM` and `TO` are pointers to a type that derives from
-/// CastableBase, and the pointee type of `TO` is of the same type as, or is an ancestor of the
-/// pointee type of `FROM`. Vectors of non-`const` Castable pointers can be converted to a vector of
-/// `const` Castable pointers.
-template <ReinterpretMode MODE, typename TO, typename FROM>
-static constexpr bool CanReinterpretSlice = detail::CanReinterpretSlice<MODE, TO, FROM>::value;
-
-/// Reinterprets `const Slice<FROM>*` as `const Slice<TO>*`
-/// @param slice a pointer to the slice to reinterpret
-/// @returns the reinterpreted slice
-/// @see CanReinterpretSlice
-template <ReinterpretMode MODE, typename TO, typename FROM>
-const Slice<TO>* ReinterpretSlice(const Slice<FROM>* slice) {
-    static_assert(CanReinterpretSlice<MODE, TO, FROM>);
-    return Bitcast<const Slice<TO>*>(slice);
-}
-
-/// Reinterprets `Slice<FROM>*` as `Slice<TO>*`
-/// @param slice a pointer to the slice to reinterpret
-/// @returns the reinterpreted slice
-/// @see CanReinterpretSlice
-template <ReinterpretMode MODE, typename TO, typename FROM>
-Slice<TO>* ReinterpretSlice(Slice<FROM>* slice) {
-    static_assert(CanReinterpretSlice<MODE, TO, FROM>);
-    return Bitcast<Slice<TO>*>(slice);
-}
-
 /// Vector is a small-object-optimized, dynamically-sized vector of contigious elements of type T.
 ///
 /// Vector will fit `N` elements internally before spilling to heap allocations. If `N` is greater
@@ -244,7 +113,7 @@
               ReinterpretMode MODE,
               typename = std::enable_if_t<CanReinterpretSlice<MODE, T, U>>>
     Vector(const Vector<U, N2>& other) {  // NOLINT(runtime/explicit)
-        Copy(*ReinterpretSlice<MODE, T>(&other.impl_.slice));
+        Copy(other.impl_.slice.template Reinterpret<T, MODE>);
     }
 
     /// Move constructor with covariance / const conversion
@@ -518,6 +387,9 @@
         return !(*this == other);
     }
 
+    /// @returns the internal slice of the vector
+    utils::Slice<T> Slice() { return impl_.slice; }
+
   private:
     /// Friend class (differing specializations of this class)
     template <typename, size_t>
@@ -531,9 +403,6 @@
     template <typename>
     friend class VectorRef;
 
-    /// The slice type used by this vector
-    using Slice = utils::Slice<T>;
-
     template <typename... Ts>
     void AppendVariadic(Ts&&... args) {
         ((new (&impl_.slice.data[impl_.slice.len++]) T(std::forward<Ts>(args))), ...);
@@ -555,7 +424,7 @@
 
     /// Copies all the elements from `other` to this vector, replacing the content of this vector.
     /// @param other the
-    void Copy(const Slice& other) {
+    void Copy(const utils::Slice<T>& other) {
         if (impl_.slice.cap < other.len) {
             ClearAndFree();
             impl_.Allocate(other.len);
@@ -592,7 +461,7 @@
     /// The internal structure for the vector with a small array.
     struct ImplWithSmallArray {
         TStorage small_arr[N];
-        Slice slice = {small_arr[0].Get(), 0, N};
+        utils::Slice<T> slice = {small_arr[0].Get(), 0, N};
 
         /// Allocates a new vector of `T` either from #small_arr, or from the heap, then assigns the
         /// pointer it to #slice.data, and updates #slice.cap.
@@ -620,7 +489,7 @@
 
     /// The internal structure for the vector without a small array.
     struct ImplWithoutSmallArray {
-        Slice slice = {nullptr, 0, 0};
+        utils::Slice<T> slice = Empty;
 
         /// Allocates a new vector of `T` and assigns it to #slice.data, and updates #slice.cap.
         void Allocate(size_t new_cap) {
@@ -759,15 +628,14 @@
     template <typename U,
               typename = std::enable_if_t<CanReinterpretSlice<ReinterpretMode::kSafe, T, U>>>
     VectorRef(const VectorRef<U>& other)  // NOLINT(runtime/explicit)
-        : slice_(*ReinterpretSlice<ReinterpretMode::kSafe, T>(&other.slice_)) {}
+        : slice_(other.slice_.template Reinterpret<T>()) {}
 
     /// Move constructor with covariance / const conversion
     /// @param other the vector reference
     template <typename U,
               typename = std::enable_if_t<CanReinterpretSlice<ReinterpretMode::kSafe, T, U>>>
     VectorRef(VectorRef<U>&& other)  // NOLINT(runtime/explicit)
-        : slice_(*ReinterpretSlice<ReinterpretMode::kSafe, T>(&other.slice_)),
-          can_move_(other.can_move_) {}
+        : slice_(other.slice_.template Reinterpret<T>()), can_move_(other.can_move_) {}
 
     /// Constructor from a Vector with covariance / const conversion
     /// @param vector the vector to create a reference of
@@ -776,7 +644,7 @@
               size_t N,
               typename = std::enable_if_t<CanReinterpretSlice<ReinterpretMode::kSafe, T, U>>>
     VectorRef(Vector<U, N>& vector)  // NOLINT(runtime/explicit)
-        : slice_(*ReinterpretSlice<ReinterpretMode::kSafe, T>(&vector.impl_.slice)) {}
+        : slice_(vector.impl_.slice.template Reinterpret<T>()) {}
 
     /// Constructor from a moved Vector with covariance / const conversion
     /// @param vector the vector to create a reference of
@@ -785,8 +653,7 @@
               size_t N,
               typename = std::enable_if_t<CanReinterpretSlice<ReinterpretMode::kSafe, T, U>>>
     VectorRef(Vector<U, N>&& vector)  // NOLINT(runtime/explicit)
-        : slice_(*ReinterpretSlice<ReinterpretMode::kSafe, T>(&vector.impl_.slice)),
-          can_move_(vector.impl_.CanMove()) {}
+        : slice_(vector.impl_.slice.template Reinterpret<T>()), can_move_(vector.impl_.CanMove()) {}
 
     /// Index operator
     /// @param i the element index. Must be less than `len`.
@@ -805,7 +672,7 @@
     /// this is a safe operation.
     template <typename U>
     VectorRef<U> ReinterpretCast() const {
-        return {*ReinterpretSlice<ReinterpretMode::kUnsafe, U>(&slice_)};
+        return {slice_.template Reinterpret<U, ReinterpretMode::kUnsafe>()};
     }
 
     /// @returns true if the vector is empty.
diff --git a/src/tint/utils/vector_test.cc b/src/tint/utils/vector_test.cc
index ed9a97a..6245476 100644
--- a/src/tint/utils/vector_test.cc
+++ b/src/tint/utils/vector_test.cc
@@ -79,31 +79,6 @@
 static_assert(std::is_same_v<VectorCommonType<C2a*, const C2b*>, const C1*>);
 static_assert(std::is_same_v<VectorCommonType<const C2a*, const C2b*>, const C1*>);
 
-static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, const C0*, C0*>, "apply const");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C0*, const C0*>, "remove const");
-static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, C0*, C1*>, "up cast");
-static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, const C0*, const C1*>, "up cast");
-static_assert(CanReinterpretSlice<ReinterpretMode::kSafe, const C0*, C1*>, "up cast, apply const");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C0*, const C1*>,
-              "up cast, remove const");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C1*, C0*>, "down cast");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C1*, const C0*>, "down cast");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C1*, C0*>,
-              "down cast, apply const");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C1*, const C0*>,
-              "down cast, remove const");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C1*, C0*>,
-              "down cast, apply const");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C1*, const C0*>,
-              "down cast, remove const");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C2a*, C2b*>, "sideways cast");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C2a*, const C2b*>,
-              "sideways cast");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, const C2a*, C2b*>,
-              "sideways cast, apply const");
-static_assert(!CanReinterpretSlice<ReinterpretMode::kSafe, C2a*, const C2b*>,
-              "sideways cast, remove const");
-
 ////////////////////////////////////////////////////////////////////////////////
 // TintVectorTest
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tint/writer/append_vector.cc b/src/tint/writer/append_vector.cc
index 3d38c7f..c31667d 100644
--- a/src/tint/writer/append_vector.cc
+++ b/src/tint/writer/append_vector.cc
@@ -18,8 +18,8 @@
 #include <vector>
 
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/value_expression.h"
 #include "src/tint/utils/transform.h"
 
@@ -28,14 +28,14 @@
 namespace tint::writer {
 namespace {
 
-struct VectorInitializerInfo {
+struct VectorConstructorInfo {
     const sem::Call* call = nullptr;
-    const sem::TypeInitializer* ctor = nullptr;
+    const sem::ValueConstructor* ctor = nullptr;
     operator bool() const { return call != nullptr; }
 };
-VectorInitializerInfo AsVectorInitializer(const sem::ValueExpression* expr) {
+VectorConstructorInfo AsVectorConstructor(const sem::ValueExpression* expr) {
     if (auto* call = expr->As<sem::Call>()) {
-        if (auto* ctor = call->Target()->As<sem::TypeInitializer>()) {
+        if (auto* ctor = call->Target()->As<sem::ValueConstructor>()) {
             if (ctor->ReturnType()->Is<type::Vector>()) {
                 return {call, ctor};
             }
@@ -103,20 +103,20 @@
     auto packed_ast_ty = b->ty.vec(packed_el_ast_ty, packed_size);
     auto* packed_sem_ty = b->create<type::Vector>(packed_el_sem_ty, packed_size);
 
-    // If the coordinates are already passed in a vector initializer, with only
+    // If the coordinates are already passed in a vector constructor, with only
     // scalar components supplied, extract the elements into the new vector
     // instead of nesting a vector-in-vector.
-    // If the coordinates are a zero-initializer of the vector, then expand that
+    // If the coordinates are a zero-constructor of the vector, then expand that
     // to scalar zeros.
-    // The other cases for a nested vector initializer are when it is used
+    // The other cases for a nested vector constructor are when it is used
     // to convert a vector of a different type, e.g. vec2<i32>(vec2<u32>()).
     // In that case, preserve the original argument, or you'll get a type error.
 
     utils::Vector<const sem::ValueExpression*, 4> packed;
-    if (auto vc = AsVectorInitializer(vector_sem)) {
+    if (auto vc = AsVectorConstructor(vector_sem)) {
         const auto num_supplied = vc.call->Arguments().Length();
         if (num_supplied == 0) {
-            // Zero-value vector initializer. Populate with zeros
+            // Zero-value vector constructor. Populate with zeros
             for (uint32_t i = 0; i < packed_size - 1; i++) {
                 auto* zero = Zero(*b, packed_el_sem_ty, statement);
                 packed.Push(zero);
@@ -134,10 +134,11 @@
     if (packed_el_sem_ty != scalar_sem->Type()->UnwrapRef()) {
         // Cast scalar to the vector element type
         auto* scalar_cast_ast = b->Call(packed_el_ast_ty, scalar_ast);
-        auto* scalar_cast_target = b->create<sem::TypeConversion>(
+        auto* scalar_cast_target = b->create<sem::ValueConversion>(
             packed_el_sem_ty,
             b->create<sem::Parameter>(nullptr, 0u, scalar_sem->Type()->UnwrapRef(),
-                                      type::AddressSpace::kNone, type::Access::kUndefined),
+                                      builtin::AddressSpace::kUndefined,
+                                      builtin::Access::kUndefined),
             sem::EvaluationStage::kRuntime);
         auto* scalar_cast_sem = b->create<sem::Call>(
             scalar_cast_ast, scalar_cast_target, sem::EvaluationStage::kRuntime,
@@ -149,27 +150,26 @@
         packed.Push(scalar_sem);
     }
 
-    auto* initializer_ast =
+    auto* ctor_ast =
         b->Call(packed_ast_ty, utils::Transform(packed, [&](const sem::ValueExpression* expr) {
                     return expr->Declaration();
                 }));
-    auto* initializer_target = b->create<sem::TypeInitializer>(
+    auto* ctor_target = b->create<sem::ValueConstructor>(
         packed_sem_ty,
         utils::Transform(
             packed,
             [&](const tint::sem::ValueExpression* arg, size_t i) -> const sem::Parameter* {
                 return b->create<sem::Parameter>(
                     nullptr, static_cast<uint32_t>(i), arg->Type()->UnwrapRef(),
-                    type::AddressSpace::kNone, type::Access::kUndefined);
+                    builtin::AddressSpace::kUndefined, builtin::Access::kUndefined);
             }),
         sem::EvaluationStage::kRuntime);
-    auto* initializer_sem =
-        b->create<sem::Call>(initializer_ast, initializer_target, sem::EvaluationStage::kRuntime,
-                             std::move(packed), statement,
-                             /* constant_value */ nullptr,
-                             /* has_side_effects */ false);
-    b->Sem().Add(initializer_ast, initializer_sem);
-    return initializer_sem;
+    auto* ctor_sem = b->create<sem::Call>(ctor_ast, ctor_target, sem::EvaluationStage::kRuntime,
+                                          std::move(packed), statement,
+                                          /* constant_value */ nullptr,
+                                          /* has_side_effects */ false);
+    b->Sem().Add(ctor_ast, ctor_sem);
+    return ctor_sem;
 }
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/append_vector.h b/src/tint/writer/append_vector.h
index 91be10b..0528c52 100644
--- a/src/tint/writer/append_vector.h
+++ b/src/tint/writer/append_vector.h
@@ -30,7 +30,7 @@
 
 /// A helper function used to append a vector with an additional scalar.
 /// If the scalar's type does not match the target vector element type,
-/// then it is value-converted (via TypeInitializer) before being added.
+/// then it is value-converted (via ValueConstructor) before being added.
 /// All types must have been assigned to the expressions and their child nodes
 /// before calling.
 /// @param builder the program builder.
diff --git a/src/tint/writer/append_vector_test.cc b/src/tint/writer/append_vector_test.cc
index feded0c..0303c3c 100644
--- a/src/tint/writer/append_vector_test.cc
+++ b/src/tint/writer/append_vector_test.cc
@@ -16,7 +16,7 @@
 #include "src/tint/ast/test_helper.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/resolver/resolver.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
 
 #include "gtest/gtest.h"
 
@@ -54,7 +54,7 @@
     EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
     EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 3u);
@@ -99,7 +99,7 @@
     EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
     EXPECT_EQ(call->Arguments()[2], Sem().Get(u32_to_i32));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 3u);
@@ -149,7 +149,7 @@
     EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
     EXPECT_EQ(call->Arguments()[1], Sem().Get(u32_to_i32));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
 
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
@@ -193,7 +193,7 @@
     EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
     EXPECT_EQ(call->Arguments()[2], Sem().Get(f32_to_i32));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 3u);
@@ -236,7 +236,7 @@
     EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
     EXPECT_EQ(call->Arguments()[3], Sem().Get(scalar_4));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 4u);
@@ -252,7 +252,7 @@
 
 // AppendVector(vec_12, 3) -> vec3<i32>(vec_12, 3)
 TEST_F(AppendVectorTest, Vec2i32Var_i32) {
-    GlobalVar("vec_12", ty.vec2<i32>(), type::AddressSpace::kPrivate);
+    GlobalVar("vec_12", ty.vec2<i32>(), builtin::AddressSpace::kPrivate);
     auto* vec_12 = Expr("vec_12");
     auto* scalar_3 = Expr(3_i);
     WrapInFunction(vec_12, scalar_3);
@@ -274,7 +274,7 @@
     EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
     EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 3u);
@@ -288,7 +288,7 @@
 
 // AppendVector(1, 2, scalar_3) -> vec3<i32>(1, 2, scalar_3)
 TEST_F(AppendVectorTest, Vec2i32_i32Var) {
-    GlobalVar("scalar_3", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("scalar_3", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* scalar_1 = Expr(1_i);
     auto* scalar_2 = Expr(2_i);
     auto* scalar_3 = Expr("scalar_3");
@@ -314,7 +314,7 @@
     EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
     EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 3u);
@@ -329,8 +329,8 @@
 
 // AppendVector(vec_12, scalar_3) -> vec3<i32>(vec_12, scalar_3)
 TEST_F(AppendVectorTest, Vec2i32Var_i32Var) {
-    GlobalVar("vec_12", ty.vec2<i32>(), type::AddressSpace::kPrivate);
-    GlobalVar("scalar_3", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("vec_12", ty.vec2<i32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("scalar_3", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* vec_12 = Expr("vec_12");
     auto* scalar_3 = Expr("scalar_3");
     WrapInFunction(vec_12, scalar_3);
@@ -352,7 +352,7 @@
     EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
     EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 3u);
@@ -366,8 +366,8 @@
 
 // AppendVector(vec_12, scalar_3) -> vec3<i32>(vec_12, i32(scalar_3))
 TEST_F(AppendVectorTest, Vec2i32Var_f32Var) {
-    GlobalVar("vec_12", ty.vec2<i32>(), type::AddressSpace::kPrivate);
-    GlobalVar("scalar_3", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("vec_12", ty.vec2<i32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("scalar_3", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* vec_12 = Expr("vec_12");
     auto* scalar_3 = Expr("scalar_3");
     WrapInFunction(vec_12, scalar_3);
@@ -393,7 +393,7 @@
     EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
     EXPECT_EQ(call->Arguments()[1], Sem().Get(f32_to_i32));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 3u);
@@ -407,8 +407,8 @@
 
 // AppendVector(vec_12, scalar_3) -> vec3<bool>(vec_12, scalar_3)
 TEST_F(AppendVectorTest, Vec2boolVar_boolVar) {
-    GlobalVar("vec_12", ty.vec2<bool>(), type::AddressSpace::kPrivate);
-    GlobalVar("scalar_3", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("vec_12", ty.vec2<bool>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("scalar_3", ty.bool_(), builtin::AddressSpace::kPrivate);
     auto* vec_12 = Expr("vec_12");
     auto* scalar_3 = Expr("scalar_3");
     WrapInFunction(vec_12, scalar_3);
@@ -430,7 +430,7 @@
     EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
     EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 3u);
@@ -471,7 +471,7 @@
     EXPECT_EQ(call->Arguments()[2], Sem().Get(vec_0004->args[2]));
     EXPECT_EQ(call->Arguments()[3], Sem().Get(scalar));
 
-    auto* ctor = call->Target()->As<sem::TypeInitializer>();
+    auto* ctor = call->Target()->As<sem::ValueConstructor>();
     ASSERT_NE(ctor, nullptr);
     ASSERT_TRUE(ctor->ReturnType()->Is<type::Vector>());
     EXPECT_EQ(ctor->ReturnType()->As<type::Vector>()->Width(), 4u);
diff --git a/src/tint/writer/flatten_bindings_test.cc b/src/tint/writer/flatten_bindings_test.cc
index 0464742..7e53356 100644
--- a/src/tint/writer/flatten_bindings_test.cc
+++ b/src/tint/writer/flatten_bindings_test.cc
@@ -39,9 +39,9 @@
 
 TEST_F(FlattenBindingsTest, AlreadyFlat) {
     ProgramBuilder b;
-    b.GlobalVar("a", b.ty.i32(), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
-    b.GlobalVar("b", b.ty.i32(), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(1_a));
-    b.GlobalVar("c", b.ty.i32(), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(2_a));
+    b.GlobalVar("a", b.ty.i32(), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("b", b.ty.i32(), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(1_a));
+    b.GlobalVar("c", b.ty.i32(), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(2_a));
 
     Program program(std::move(b));
     ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
@@ -52,9 +52,9 @@
 
 TEST_F(FlattenBindingsTest, NotFlat_SingleNamespace) {
     ProgramBuilder b;
-    b.GlobalVar("a", b.ty.i32(), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
-    b.GlobalVar("b", b.ty.i32(), type::AddressSpace::kUniform, b.Group(1_a), b.Binding(1_a));
-    b.GlobalVar("c", b.ty.i32(), type::AddressSpace::kUniform, b.Group(2_a), b.Binding(2_a));
+    b.GlobalVar("a", b.ty.i32(), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
+    b.GlobalVar("b", b.ty.i32(), builtin::AddressSpace::kUniform, b.Group(1_a), b.Binding(1_a));
+    b.GlobalVar("c", b.ty.i32(), builtin::AddressSpace::kUniform, b.Group(2_a), b.Binding(2_a));
     b.WrapInFunction(b.Expr("a"), b.Expr("b"), b.Expr("c"));
 
     Program program(std::move(b));
@@ -85,9 +85,11 @@
     ProgramBuilder b;
 
     const size_t num_buffers = 3;
-    b.GlobalVar("buffer1", b.ty.i32(), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
-    b.GlobalVar("buffer2", b.ty.i32(), type::AddressSpace::kStorage, b.Group(1_a), b.Binding(1_a));
-    b.GlobalVar("buffer3", b.ty.i32(), type::AddressSpace::kStorage, type::Access::kRead,
+    b.GlobalVar("buffer1", b.ty.i32(), builtin::AddressSpace::kUniform, b.Group(0_a),
+                b.Binding(0_a));
+    b.GlobalVar("buffer2", b.ty.i32(), builtin::AddressSpace::kStorage, b.Group(1_a),
+                b.Binding(1_a));
+    b.GlobalVar("buffer3", b.ty.i32(), builtin::AddressSpace::kStorage, builtin::Access::kRead,
                 b.Group(2_a), b.Binding(2_a));
 
     const size_t num_samplers = 2;
@@ -102,8 +104,8 @@
     b.GlobalVar("texture2", b.ty.multisampled_texture(type::TextureDimension::k2d, b.ty.f32()),
                 b.Group(6_a), b.Binding(6_a));
     b.GlobalVar("texture3",
-                b.ty.storage_texture(type::TextureDimension::k2d, type::TexelFormat::kR32Float,
-                                     type::Access::kWrite),
+                b.ty.storage_texture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Float,
+                                     builtin::Access::kWrite),
                 b.Group(7_a), b.Binding(7_a));
     b.GlobalVar("texture4", b.ty.depth_texture(type::TextureDimension::k2d), b.Group(8_a),
                 b.Binding(8_a));
diff --git a/src/tint/writer/generate_external_texture_bindings_test.cc b/src/tint/writer/generate_external_texture_bindings_test.cc
index e441517..d6b22ac 100644
--- a/src/tint/writer/generate_external_texture_bindings_test.cc
+++ b/src/tint/writer/generate_external_texture_bindings_test.cc
@@ -23,7 +23,7 @@
 
 using namespace tint::number_suffixes;  // NOLINT
 
-constexpr auto kUniform = type::AddressSpace::kUniform;
+constexpr auto kUniform = builtin::AddressSpace::kUniform;
 
 class GenerateExternalTextureBindingsTest : public ::testing::Test {};
 
diff --git a/src/tint/writer/glsl/generator.h b/src/tint/writer/glsl/generator.h
index 60d5aa1..4d31bdf 100644
--- a/src/tint/writer/glsl/generator.h
+++ b/src/tint/writer/glsl/generator.h
@@ -22,9 +22,9 @@
 #include <vector>
 
 #include "src/tint/ast/pipeline_stage.h"
+#include "src/tint/builtin/access.h"
 #include "src/tint/sem/binding_point.h"
 #include "src/tint/sem/sampler_texture_pair.h"
-#include "src/tint/type/access.h"
 #include "src/tint/writer/glsl/version.h"
 #include "src/tint/writer/text.h"
 
@@ -61,7 +61,7 @@
 
     /// A map of old binding point to new access control for the BindingRemapper
     /// transform
-    std::unordered_map<sem::BindingPoint, type::Access> access_controls;
+    std::unordered_map<sem::BindingPoint, builtin::Access> access_controls;
 
     /// If true, then validation will be disabled for binding point collisions
     /// generated by the BindingRemapper transform
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index a09af2f..e8b5b9b 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -36,8 +36,8 @@
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/switch_statement.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/transform/add_block_attribute.h"
 #include "src/tint/transform/add_empty_entry_point.h"
@@ -374,7 +374,8 @@
                dst_type->is_float_scalar_or_vector()) {
         out << "uintBitsToFloat";
     } else {
-        if (!EmitType(out, dst_type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+        if (!EmitType(out, dst_type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                      "")) {
             return false;
         }
     }
@@ -437,12 +438,14 @@
     auto* uint_type = BoolTypeToUint(bool_type);
 
     // Cast result to bool scalar or vector type.
-    if (!EmitType(out, bool_type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+    if (!EmitType(out, bool_type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                  "")) {
         return false;
     }
     ScopedParen outerCastParen(out);
     // Cast LHS to uint scalar or vector type.
-    if (!EmitType(out, uint_type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+    if (!EmitType(out, uint_type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                  "")) {
         return false;
     }
     {
@@ -462,7 +465,8 @@
         return false;
     }
     // Cast RHS to uint scalar or vector type.
-    if (!EmitType(out, uint_type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+    if (!EmitType(out, uint_type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                  "")) {
         return false;
     }
     {
@@ -480,43 +484,43 @@
     auto* ret_ty = TypeOf(expr)->UnwrapRef();
     auto* lhs_ty = TypeOf(expr->lhs)->UnwrapRef();
     auto* rhs_ty = TypeOf(expr->rhs)->UnwrapRef();
-    fn = utils::GetOrCreate(float_modulo_funcs_, BinaryOperandType{{lhs_ty, rhs_ty}},
-                            [&]() -> std::string {
-                                TextBuffer b;
-                                TINT_DEFER(helpers_.Append(b));
+    fn = utils::GetOrCreate(
+        float_modulo_funcs_, BinaryOperandType{{lhs_ty, rhs_ty}}, [&]() -> std::string {
+            TextBuffer b;
+            TINT_DEFER(helpers_.Append(b));
 
-                                auto fn_name = UniqueIdentifier("tint_float_modulo");
-                                std::vector<std::string> parameter_names;
-                                {
-                                    auto decl = line(&b);
-                                    if (!EmitTypeAndName(decl, ret_ty, type::AddressSpace::kNone,
-                                                         type::Access::kUndefined, fn_name)) {
-                                        return "";
-                                    }
-                                    {
-                                        ScopedParen sp(decl);
-                                        const auto* ty = TypeOf(expr->lhs)->UnwrapRef();
-                                        if (!EmitTypeAndName(decl, ty, type::AddressSpace::kNone,
-                                                             type::Access::kUndefined, "lhs")) {
-                                            return "";
-                                        }
-                                        decl << ", ";
-                                        ty = TypeOf(expr->rhs)->UnwrapRef();
-                                        if (!EmitTypeAndName(decl, ty, type::AddressSpace::kNone,
-                                                             type::Access::kUndefined, "rhs")) {
-                                            return "";
-                                        }
-                                    }
-                                    decl << " {";
-                                }
-                                {
-                                    ScopedIndent si(&b);
-                                    line(&b) << "return (lhs - rhs * trunc(lhs / rhs));";
-                                }
-                                line(&b) << "}";
-                                line(&b);
-                                return fn_name;
-                            });
+            auto fn_name = UniqueIdentifier("tint_float_modulo");
+            std::vector<std::string> parameter_names;
+            {
+                auto decl = line(&b);
+                if (!EmitTypeAndName(decl, ret_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, fn_name)) {
+                    return "";
+                }
+                {
+                    ScopedParen sp(decl);
+                    const auto* ty = TypeOf(expr->lhs)->UnwrapRef();
+                    if (!EmitTypeAndName(decl, ty, builtin::AddressSpace::kUndefined,
+                                         builtin::Access::kUndefined, "lhs")) {
+                        return "";
+                    }
+                    decl << ", ";
+                    ty = TypeOf(expr->rhs)->UnwrapRef();
+                    if (!EmitTypeAndName(decl, ty, builtin::AddressSpace::kUndefined,
+                                         builtin::Access::kUndefined, "rhs")) {
+                        return "";
+                    }
+                }
+                decl << " {";
+            }
+            {
+                ScopedIndent si(&b);
+                line(&b) << "return (lhs - rhs * trunc(lhs / rhs));";
+            }
+            line(&b) << "}";
+            line(&b);
+            return fn_name;
+        });
 
     if (fn.empty()) {
         return false;
@@ -708,8 +712,8 @@
         call->Target(),  //
         [&](const sem::Function* fn) { return EmitFunctionCall(out, call, fn); },
         [&](const sem::Builtin* builtin) { return EmitBuiltinCall(out, call, builtin); },
-        [&](const sem::TypeConversion* conv) { return EmitTypeConversion(out, call, conv); },
-        [&](const sem::TypeInitializer* init) { return EmitTypeInitializer(out, call, init); },
+        [&](const sem::ValueConversion* conv) { return EmitValueConversion(out, call, conv); },
+        [&](const sem::ValueConstructor* ctor) { return EmitValueConstructor(out, call, ctor); },
         [&](Default) {
             TINT_ICE(Writer, diagnostics_)
                 << "unhandled call target: " << call->Target()->TypeInfo().name;
@@ -823,10 +827,11 @@
     return true;
 }
 
-bool GeneratorImpl::EmitTypeConversion(std::ostream& out,
-                                       const sem::Call* call,
-                                       const sem::TypeConversion* conv) {
-    if (!EmitType(out, conv->Target(), type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+bool GeneratorImpl::EmitValueConversion(std::ostream& out,
+                                        const sem::Call* call,
+                                        const sem::ValueConversion* conv) {
+    if (!EmitType(out, conv->Target(), builtin::AddressSpace::kUndefined,
+                  builtin::Access::kReadWrite, "")) {
         return false;
     }
     ScopedParen sp(out);
@@ -838,18 +843,18 @@
     return true;
 }
 
-bool GeneratorImpl::EmitTypeInitializer(std::ostream& out,
-                                        const sem::Call* call,
-                                        const sem::TypeInitializer* ctor) {
+bool GeneratorImpl::EmitValueConstructor(std::ostream& out,
+                                         const sem::Call* call,
+                                         const sem::ValueConstructor* ctor) {
     auto* type = ctor->ReturnType();
 
-    // If the type initializer is empty then we need to construct with the zero
-    // value for all components.
+    // If the value constructor is empty then we need to construct with the zero value for all
+    // components.
     if (call->Arguments().IsEmpty()) {
         return EmitZeroValue(out, type);
     }
 
-    if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+    if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, "")) {
         return false;
     }
     ScopedParen sp(out);
@@ -919,8 +924,8 @@
 
             {
                 auto pre = line();
-                if (!EmitTypeAndName(pre, builtin->ReturnType(), type::AddressSpace::kNone,
-                                     type::Access::kUndefined, result)) {
+                if (!EmitTypeAndName(pre, builtin->ReturnType(), builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, result)) {
                     return false;
                 }
                 pre << ";";
@@ -1057,8 +1062,8 @@
 bool GeneratorImpl::EmitCountOneBitsCall(std::ostream& out, const ast::CallExpression* expr) {
     // GLSL's bitCount returns an integer type, so cast it to the appropriate
     // unsigned type.
-    if (!EmitType(out, TypeOf(expr)->UnwrapRef(), type::AddressSpace::kNone,
-                  type::Access::kReadWrite, "")) {
+    if (!EmitType(out, TypeOf(expr)->UnwrapRef(), builtin::AddressSpace::kUndefined,
+                  builtin::Access::kReadWrite, "")) {
         return false;
     }
     out << "(bitCount(";
@@ -1129,24 +1134,26 @@
             std::string v;
             {
                 std::stringstream s;
-                if (!EmitType(s, vec_ty->type(), type::AddressSpace::kNone, type::Access::kRead,
-                              "")) {
+                if (!EmitType(s, vec_ty->type(), builtin::AddressSpace::kUndefined,
+                              builtin::Access::kRead, "")) {
                     return "";
                 }
                 v = s.str();
             }
             {  // (u)int tint_int_dot([i|u]vecN a, [i|u]vecN b) {
                 auto l = line(&b);
-                if (!EmitType(l, vec_ty->type(), type::AddressSpace::kNone, type::Access::kRead,
-                              "")) {
+                if (!EmitType(l, vec_ty->type(), builtin::AddressSpace::kUndefined,
+                              builtin::Access::kRead, "")) {
                     return "";
                 }
                 l << " " << fn_name << "(";
-                if (!EmitType(l, vec_ty, type::AddressSpace::kNone, type::Access::kRead, "")) {
+                if (!EmitType(l, vec_ty, builtin::AddressSpace::kUndefined, builtin::Access::kRead,
+                              "")) {
                     return "";
                 }
                 l << " a, ";
-                if (!EmitType(l, vec_ty, type::AddressSpace::kNone, type::Access::kRead, "")) {
+                if (!EmitType(l, vec_ty, builtin::AddressSpace::kUndefined, builtin::Access::kRead,
+                              "")) {
                     return "";
                 }
                 l << " b) {";
@@ -1197,8 +1204,8 @@
 
             {
                 auto l = line(b);
-                if (!EmitType(l, builtin->ReturnType(), type::AddressSpace::kNone,
-                              type::Access::kUndefined, "")) {
+                if (!EmitType(l, builtin->ReturnType(), builtin::AddressSpace::kUndefined,
+                              builtin::Access::kUndefined, "")) {
                     return false;
                 }
                 l << " result;";
@@ -1223,8 +1230,8 @@
 
             {
                 auto l = line(b);
-                if (!EmitType(l, builtin->ReturnType(), type::AddressSpace::kNone,
-                              type::Access::kUndefined, "")) {
+                if (!EmitType(l, builtin->ReturnType(), builtin::AddressSpace::kUndefined,
+                              builtin::Access::kUndefined, "")) {
                     return false;
                 }
                 l << " result;";
@@ -1881,8 +1888,8 @@
     {
         auto out = line();
         auto name = builder_.Symbols().NameFor(func->name->symbol);
-        if (!EmitType(out, sem->ReturnType(), type::AddressSpace::kNone, type::Access::kReadWrite,
-                      "")) {
+        if (!EmitType(out, sem->ReturnType(), builtin::AddressSpace::kUndefined,
+                      builtin::Access::kReadWrite, "")) {
             return false;
         }
 
@@ -1907,7 +1914,7 @@
                 type = ptr->StoreType();
             }
 
-            // Note: WGSL only allows for AddressSpace::kNone on parameters, however
+            // Note: WGSL only allows for AddressSpace::kUndefined on parameters, however
             // the sanitizer transforms generates load / store functions for storage
             // or uniform buffers. These functions have a buffer parameter with
             // AddressSpace::kStorage or AddressSpace::kUniform. This is required to
@@ -1937,20 +1944,20 @@
         [&](const ast::Var* var) {
             auto* sem = builder_.Sem().Get<sem::GlobalVariable>(global);
             switch (sem->AddressSpace()) {
-                case type::AddressSpace::kUniform:
+                case builtin::AddressSpace::kUniform:
                     return EmitUniformVariable(var, sem);
-                case type::AddressSpace::kStorage:
+                case builtin::AddressSpace::kStorage:
                     return EmitStorageVariable(var, sem);
-                case type::AddressSpace::kHandle:
+                case builtin::AddressSpace::kHandle:
                     return EmitHandleVariable(var, sem);
-                case type::AddressSpace::kPrivate:
+                case builtin::AddressSpace::kPrivate:
                     return EmitPrivateVariable(sem);
-                case type::AddressSpace::kWorkgroup:
+                case builtin::AddressSpace::kWorkgroup:
                     return EmitWorkgroupVariable(sem);
-                case type::AddressSpace::kIn:
-                case type::AddressSpace::kOut:
+                case builtin::AddressSpace::kIn:
+                case builtin::AddressSpace::kOut:
                     return EmitIOVariable(sem);
-                case type::AddressSpace::kPushConstant:
+                case builtin::AddressSpace::kPushConstant:
                     diagnostics_.add_error(
                         diag::System::Writer,
                         "unhandled address space " + utils::ToString(sem->AddressSpace()));
@@ -2031,59 +2038,59 @@
     if (auto* storage = type->As<type::StorageTexture>()) {
         out << "layout(";
         switch (storage->texel_format()) {
-            case type::TexelFormat::kBgra8Unorm:
+            case builtin::TexelFormat::kBgra8Unorm:
                 TINT_ICE(Writer, diagnostics_)
                     << "bgra8unorm should have been polyfilled to rgba8unorm";
                 break;
-            case type::TexelFormat::kR32Uint:
+            case builtin::TexelFormat::kR32Uint:
                 out << "r32ui";
                 break;
-            case type::TexelFormat::kR32Sint:
+            case builtin::TexelFormat::kR32Sint:
                 out << "r32i";
                 break;
-            case type::TexelFormat::kR32Float:
+            case builtin::TexelFormat::kR32Float:
                 out << "r32f";
                 break;
-            case type::TexelFormat::kRgba8Unorm:
+            case builtin::TexelFormat::kRgba8Unorm:
                 out << "rgba8";
                 break;
-            case type::TexelFormat::kRgba8Snorm:
+            case builtin::TexelFormat::kRgba8Snorm:
                 out << "rgba8_snorm";
                 break;
-            case type::TexelFormat::kRgba8Uint:
+            case builtin::TexelFormat::kRgba8Uint:
                 out << "rgba8ui";
                 break;
-            case type::TexelFormat::kRgba8Sint:
+            case builtin::TexelFormat::kRgba8Sint:
                 out << "rgba8i";
                 break;
-            case type::TexelFormat::kRg32Uint:
+            case builtin::TexelFormat::kRg32Uint:
                 out << "rg32ui";
                 break;
-            case type::TexelFormat::kRg32Sint:
+            case builtin::TexelFormat::kRg32Sint:
                 out << "rg32i";
                 break;
-            case type::TexelFormat::kRg32Float:
+            case builtin::TexelFormat::kRg32Float:
                 out << "rg32f";
                 break;
-            case type::TexelFormat::kRgba16Uint:
+            case builtin::TexelFormat::kRgba16Uint:
                 out << "rgba16ui";
                 break;
-            case type::TexelFormat::kRgba16Sint:
+            case builtin::TexelFormat::kRgba16Sint:
                 out << "rgba16i";
                 break;
-            case type::TexelFormat::kRgba16Float:
+            case builtin::TexelFormat::kRgba16Float:
                 out << "rgba16f";
                 break;
-            case type::TexelFormat::kRgba32Uint:
+            case builtin::TexelFormat::kRgba32Uint:
                 out << "rgba32ui";
                 break;
-            case type::TexelFormat::kRgba32Sint:
+            case builtin::TexelFormat::kRgba32Sint:
                 out << "rgba32i";
                 break;
-            case type::TexelFormat::kRgba32Float:
+            case builtin::TexelFormat::kRgba32Float:
                 out << "rgba32f";
                 break;
-            case type::TexelFormat::kUndefined:
+            case builtin::TexelFormat::kUndefined:
                 TINT_ICE(Writer, diagnostics_) << "invalid texel format";
                 return false;
         }
@@ -2148,9 +2155,10 @@
 bool GeneratorImpl::EmitIOVariable(const sem::GlobalVariable* var) {
     auto* decl = var->Declaration();
 
-    if (auto* b = ast::GetAttribute<ast::BuiltinAttribute>(decl->attributes)) {
+    if (auto* attr = ast::GetAttribute<ast::BuiltinAttribute>(decl->attributes)) {
+        auto builtin = program_->Sem().Get(attr)->Value();
         // Use of gl_SampleID requires the GL_OES_sample_variables extension
-        if (RequiresOESSampleVariables(b->builtin)) {
+        if (RequiresOESSampleVariables(builtin)) {
             requires_oes_sample_variables_ = true;
         }
         // Do not emit builtin (gl_) variables.
@@ -2183,23 +2191,33 @@
     utils::VectorRef<const ast::Attribute*> attributes) {
     for (auto* attr : attributes) {
         if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
-            switch (interpolate->type) {
-                case ast::InterpolationType::kPerspective:
-                case ast::InterpolationType::kLinear:
-                case ast::InterpolationType::kUndefined:
+            auto& sem = program_->Sem();
+            auto i_type =
+                sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(interpolate->type)
+                    ->Value();
+            switch (i_type) {
+                case builtin::InterpolationType::kPerspective:
+                case builtin::InterpolationType::kLinear:
+                case builtin::InterpolationType::kUndefined:
                     break;
-                case ast::InterpolationType::kFlat:
+                case builtin::InterpolationType::kFlat:
                     out << "flat ";
                     break;
             }
-            switch (interpolate->sampling) {
-                case ast::InterpolationSampling::kCentroid:
-                    out << "centroid ";
-                    break;
-                case ast::InterpolationSampling::kSample:
-                case ast::InterpolationSampling::kCenter:
-                case ast::InterpolationSampling::kUndefined:
-                    break;
+
+            if (interpolate->sampling) {
+                auto i_smpl = sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
+                                     interpolate->sampling)
+                                  ->Value();
+                switch (i_smpl) {
+                    case builtin::InterpolationSampling::kCentroid:
+                        out << "centroid ";
+                        break;
+                    case builtin::InterpolationSampling::kSample:
+                    case builtin::InterpolationSampling::kCenter:
+                    case builtin::InterpolationSampling::kUndefined:
+                        break;
+                }
             }
         }
     }
@@ -2258,8 +2276,8 @@
     // Emit original entry point signature
     {
         auto out = line();
-        if (!EmitTypeAndName(out, func_sem->ReturnType(), type::AddressSpace::kUndefined,
-                             type::Access::kUndefined,
+        if (!EmitTypeAndName(out, func_sem->ReturnType(), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kUndefined,
                              builder_.Symbols().NameFor(func->name->symbol))) {
             return false;
         }
@@ -2339,7 +2357,8 @@
             return true;
         },
         [&](const type::Vector* v) {
-            if (!EmitType(out, v, type::AddressSpace::kNone, type::Access::kUndefined, "")) {
+            if (!EmitType(out, v, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
+                          "")) {
                 return false;
             }
 
@@ -2360,7 +2379,8 @@
             return true;
         },
         [&](const type::Matrix* m) {
-            if (!EmitType(out, m, type::AddressSpace::kNone, type::Access::kUndefined, "")) {
+            if (!EmitType(out, m, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
+                          "")) {
                 return false;
             }
 
@@ -2377,7 +2397,8 @@
             return true;
         },
         [&](const type::Array* a) {
-            if (!EmitType(out, a, type::AddressSpace::kNone, type::Access::kUndefined, "")) {
+            if (!EmitType(out, a, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
+                          "")) {
                 return false;
             }
 
@@ -2469,7 +2490,8 @@
     } else if (type->Is<type::U32>()) {
         out << "0u";
     } else if (auto* vec = type->As<type::Vector>()) {
-        if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+        if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                      "")) {
             return false;
         }
         ScopedParen sp(out);
@@ -2482,7 +2504,8 @@
             }
         }
     } else if (auto* mat = type->As<type::Matrix>()) {
-        if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+        if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                      "")) {
             return false;
         }
         ScopedParen sp(out);
@@ -2495,7 +2518,8 @@
             }
         }
     } else if (auto* str = type->As<sem::Struct>()) {
-        if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kUndefined, "")) {
+        if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
+                      "")) {
             return false;
         }
         bool first = true;
@@ -2509,7 +2533,8 @@
             EmitZeroValue(out, member->Type());
         }
     } else if (auto* arr = type->As<type::Array>()) {
-        if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kUndefined, "")) {
+        if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
+                      "")) {
             return false;
         }
         ScopedParen sp(out);
@@ -2834,24 +2859,24 @@
 
 bool GeneratorImpl::EmitType(std::ostream& out,
                              const type::Type* type,
-                             type::AddressSpace address_space,
-                             type::Access access,
+                             builtin::AddressSpace address_space,
+                             builtin::Access access,
                              const std::string& name,
                              bool* name_printed /* = nullptr */) {
     if (name_printed) {
         *name_printed = false;
     }
     switch (address_space) {
-        case type::AddressSpace::kIn: {
+        case builtin::AddressSpace::kIn: {
             out << "in ";
             break;
         }
-        case type::AddressSpace::kOut: {
+        case builtin::AddressSpace::kOut: {
             out << "out ";
             break;
         }
-        case type::AddressSpace::kUniform:
-        case type::AddressSpace::kHandle: {
+        case builtin::AddressSpace::kUniform:
+        case builtin::AddressSpace::kHandle: {
             out << "uniform ";
             break;
         }
@@ -2932,7 +2957,7 @@
 
         out << "highp ";
 
-        if (storage && storage->access() != type::Access::kRead) {
+        if (storage && storage->access() != builtin::Access::kRead) {
             out << "writeonly ";
         }
         auto* subtype = sampled   ? sampled->type()
@@ -3015,8 +3040,8 @@
 
 bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
                                     const type::Type* type,
-                                    type::AddressSpace address_space,
-                                    type::Access access,
+                                    builtin::AddressSpace address_space,
+                                    builtin::Access access,
                                     const std::string& name) {
     bool printed_name = false;
     if (!EmitType(out, type, address_space, access, name, &printed_name)) {
@@ -3052,7 +3077,8 @@
 
         auto out = line(b);
 
-        if (!EmitTypeAndName(out, ty, type::AddressSpace::kNone, type::Access::kReadWrite, name)) {
+        if (!EmitTypeAndName(out, ty, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, name)) {
             return false;
         }
         out << ";";
@@ -3120,7 +3146,7 @@
 
     auto out = line();
     // TODO(senorblanco): handle const
-    if (!EmitTypeAndName(out, type, type::AddressSpace::kNone, type::Access::kUndefined,
+    if (!EmitTypeAndName(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
                          builder_.Symbols().NameFor(let->name->symbol))) {
         return false;
     }
@@ -3142,7 +3168,7 @@
 
     auto out = line();
     out << "const ";
-    if (!EmitTypeAndName(out, type, type::AddressSpace::kNone, type::Access::kUndefined,
+    if (!EmitTypeAndName(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
                          builder_.Symbols().NameFor(var->name->symbol))) {
         return false;
     }
@@ -3169,8 +3195,8 @@
         std::vector<std::string> parameter_names;
         {
             auto decl = line(&b);
-            if (!EmitTypeAndName(decl, builtin->ReturnType(), type::AddressSpace::kNone,
-                                 type::Access::kUndefined, fn_name)) {
+            if (!EmitTypeAndName(decl, builtin->ReturnType(), builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, fn_name)) {
                 return "";
             }
             {
@@ -3185,8 +3211,8 @@
                         decl << "inout ";
                         ty = ptr->StoreType();
                     }
-                    if (!EmitTypeAndName(decl, ty, type::AddressSpace::kNone,
-                                         type::Access::kUndefined, param_name)) {
+                    if (!EmitTypeAndName(decl, ty, builtin::AddressSpace::kUndefined,
+                                         builtin::Access::kUndefined, param_name)) {
                         return "";
                     }
                     parameter_names.emplace_back(std::move(param_name));
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index 71fb23e..d220877 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -32,6 +32,7 @@
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/switch_statement.h"
 #include "src/tint/ast/unary_op_expression.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/scope_stack.h"
 #include "src/tint/transform/decompose_memory_access.h"
@@ -42,10 +43,10 @@
 
 // Forward declarations
 namespace tint::sem {
-class Call;
 class Builtin;
-class TypeInitializer;
-class TypeConversion;
+class Call;
+class ValueConstructor;
+class ValueConversion;
 }  // namespace tint::sem
 
 namespace tint::writer::glsl {
@@ -159,22 +160,22 @@
     /// @param builtin the builtin being called
     /// @returns true if the expression is emitted
     bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
-    /// Handles generating a type conversion expression
+    /// Handles generating a value conversion expression
     /// @param out the output of the expression stream
     /// @param call the call expression
-    /// @param conv the type conversion
+    /// @param conv the value conversion
     /// @returns true if the expression is emitted
-    bool EmitTypeConversion(std::ostream& out,
-                            const sem::Call* call,
-                            const sem::TypeConversion* conv);
-    /// Handles generating a type initializer expression
-    /// @param out the output of the expression stream
-    /// @param call the call expression
-    /// @param ctor the type initializer
-    /// @returns true if the expression is emitted
-    bool EmitTypeInitializer(std::ostream& out,
+    bool EmitValueConversion(std::ostream& out,
                              const sem::Call* call,
-                             const sem::TypeInitializer* ctor);
+                             const sem::ValueConversion* conv);
+    /// Handles generating a value constructor expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param ctor the value constructor
+    /// @returns true if the expression is emitted
+    bool EmitValueConstructor(std::ostream& out,
+                              const sem::Call* call,
+                              const sem::ValueConstructor* ctor);
     /// Handles generating a barrier builtin call
     /// @param out the output of the expression stream
     /// @param builtin the semantic information for the barrier builtin
@@ -414,8 +415,8 @@
     /// @returns true if the type is emitted
     bool EmitType(std::ostream& out,
                   const type::Type* type,
-                  type::AddressSpace address_space,
-                  type::Access access,
+                  builtin::AddressSpace address_space,
+                  builtin::Access access,
                   const std::string& name,
                   bool* name_printed = nullptr);
     /// Handles generating type and name
@@ -427,8 +428,8 @@
     /// @returns true if the type is emitted
     bool EmitTypeAndName(std::ostream& out,
                          const type::Type* type,
-                         type::AddressSpace address_space,
-                         type::Access access,
+                         builtin::AddressSpace address_space,
+                         builtin::Access access,
                          const std::string& name);
     /// Handles generating a structure declaration. If the structure has already been emitted, then
     /// this function will simply return `true` without emitting anything.
diff --git a/src/tint/writer/glsl/generator_impl_array_accessor_test.cc b/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
index cee4506..bd405d3 100644
--- a/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
@@ -22,7 +22,7 @@
 using GlslGeneratorImplTest_Expression = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Expression, IndexAccessor) {
-    GlobalVar("ary", ty.array<i32, 10>(), type::AddressSpace::kPrivate);
+    GlobalVar("ary", ty.array<i32, 10>(), builtin::AddressSpace::kPrivate);
     auto* expr = IndexAccessor("ary", 5_i);
     WrapInFunction(expr);
 
diff --git a/src/tint/writer/glsl/generator_impl_assign_test.cc b/src/tint/writer/glsl/generator_impl_assign_test.cc
index 73d950c..d53d39f 100644
--- a/src/tint/writer/glsl/generator_impl_assign_test.cc
+++ b/src/tint/writer/glsl/generator_impl_assign_test.cc
@@ -20,8 +20,8 @@
 using GlslGeneratorImplTest_Assign = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Assign, Emit_Assign) {
-    GlobalVar("lhs", ty.i32(), type::AddressSpace::kPrivate);
-    GlobalVar("rhs", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("lhs", ty.i32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* assign = Assign("lhs", "rhs");
     WrapInFunction(assign);
 
diff --git a/src/tint/writer/glsl/generator_impl_binary_test.cc b/src/tint/writer/glsl/generator_impl_binary_test.cc
index 72eddc7..f90a428 100644
--- a/src/tint/writer/glsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/glsl/generator_impl_binary_test.cc
@@ -43,8 +43,8 @@
         return;
     }
 
-    GlobalVar("left", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("right", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("left", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* left = Expr("left");
     auto* right = Expr("right");
@@ -71,8 +71,8 @@
 
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("left", ty.f16(), type::AddressSpace::kPrivate);
-    GlobalVar("right", ty.f16(), type::AddressSpace::kPrivate);
+    GlobalVar("left", ty.f16(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", ty.f16(), builtin::AddressSpace::kPrivate);
 
     auto* left = Expr("left");
     auto* right = Expr("right");
@@ -90,8 +90,8 @@
 TEST_P(GlslBinaryTest, Emit_u32) {
     auto params = GetParam();
 
-    GlobalVar("left", ty.u32(), type::AddressSpace::kPrivate);
-    GlobalVar("right", ty.u32(), type::AddressSpace::kPrivate);
+    GlobalVar("left", ty.u32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", ty.u32(), builtin::AddressSpace::kPrivate);
 
     auto* left = Expr("left");
     auto* right = Expr("right");
@@ -114,8 +114,8 @@
         return;
     }
 
-    GlobalVar("left", ty.i32(), type::AddressSpace::kPrivate);
-    GlobalVar("right", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("left", ty.i32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* left = Expr("left");
     auto* right = Expr("right");
@@ -151,7 +151,7 @@
                     BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar_f32) {
-    GlobalVar("a", vec3<f32>(1_f, 1_f, 1_f), type::AddressSpace::kPrivate);
+    GlobalVar("a", vec3<f32>(1_f, 1_f, 1_f), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("a");
     auto* rhs = Expr(1_f);
 
@@ -169,7 +169,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", vec3<f16>(1_h, 1_h, 1_h), type::AddressSpace::kPrivate);
+    GlobalVar("a", vec3<f16>(1_h, 1_h, 1_h), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("a");
     auto* rhs = Expr(1_h);
 
@@ -185,7 +185,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector_f32) {
-    GlobalVar("a", vec3<f32>(1_f, 1_f, 1_f), type::AddressSpace::kPrivate);
+    GlobalVar("a", vec3<f32>(1_f, 1_f, 1_f), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr(1_f);
     auto* rhs = Expr("a");
 
@@ -203,7 +203,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", vec3<f16>(1_h, 1_h, 1_h), type::AddressSpace::kPrivate);
+    GlobalVar("a", vec3<f16>(1_h, 1_h, 1_h), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr(1_h);
     auto* rhs = Expr("a");
 
@@ -219,7 +219,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f32) {
-    GlobalVar("mat", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
     auto* rhs = Expr(1_f);
 
@@ -236,7 +236,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
     auto* rhs = Expr(1_h);
 
@@ -251,7 +251,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f32) {
-    GlobalVar("mat", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr(1_f);
     auto* rhs = Expr("mat");
 
@@ -268,7 +268,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr(1_h);
     auto* rhs = Expr("mat");
 
@@ -283,7 +283,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector_f32) {
-    GlobalVar("mat", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
     auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
 
@@ -300,7 +300,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
     auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
 
@@ -315,7 +315,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f32) {
-    GlobalVar("mat", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
     auto* rhs = Expr("mat");
 
@@ -332,7 +332,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
     auto* rhs = Expr("mat");
 
@@ -347,8 +347,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f32) {
-    GlobalVar("lhs", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("rhs", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("lhs", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -363,8 +363,8 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("lhs", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
-    GlobalVar("rhs", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("lhs", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -377,8 +377,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModF32) {
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -393,8 +393,8 @@
 TEST_F(GlslGeneratorImplTest_Binary, ModF16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", ty.f16(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.f16(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f16(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.f16(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -407,8 +407,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModVec3F32) {
-    GlobalVar("a", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -423,8 +423,8 @@
 TEST_F(GlslGeneratorImplTest_Binary, ModVec3F16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.vec3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -437,8 +437,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModVec3F32ScalarF32) {
-    GlobalVar("a", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -453,8 +453,8 @@
 TEST_F(GlslGeneratorImplTest_Binary, ModVec3F16ScalarF16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.f16(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.f16(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -467,8 +467,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModScalarF32Vec3F32) {
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -483,8 +483,8 @@
 TEST_F(GlslGeneratorImplTest_Binary, ModScalarF16Vec3F16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", ty.f16(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.vec3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f16(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -497,8 +497,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModMixedVec3ScalarF32) {
-    GlobalVar("a", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* expr_vec_mod_vec =
         create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("a"));
@@ -541,8 +541,8 @@
 TEST_F(GlslGeneratorImplTest_Binary, ModMixedVec3ScalarF16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.f16(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.f16(), builtin::AddressSpace::kPrivate);
 
     auto* expr_vec_mod_vec =
         create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("a"));
@@ -584,8 +584,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Logical_And) {
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -604,10 +604,10 @@
 
 TEST_F(GlslGeneratorImplTest_Binary, Logical_Multi) {
     // (a && b) || (c || d)
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("d", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(
         ast::BinaryOp::kLogicalOr,
@@ -636,8 +636,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Logical_Or) {
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -663,9 +663,9 @@
     //   return 3i;
     // }
 
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr =
         If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
@@ -700,9 +700,9 @@
 TEST_F(GlslGeneratorImplTest_Binary, Return_WithLogical) {
     // return (a && b) || c;
 
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Return(create<ast::BinaryExpression>(
         ast::BinaryOp::kLogicalOr,
@@ -728,10 +728,10 @@
 TEST_F(GlslGeneratorImplTest_Binary, Assign_WithLogical) {
     // a = (b || c) && d;
 
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("d", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr =
         Assign(Expr("a"),
@@ -759,9 +759,9 @@
 TEST_F(GlslGeneratorImplTest_Binary, Decl_WithLogical) {
     // var a : bool = (b && c) || d;
 
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("d", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* var =
         Var("a", ty.bool_(),
@@ -798,10 +798,10 @@
              Param(Sym(), ty.bool_()),
          },
          ty.void_(), utils::Empty, utils::Empty);
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("d", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     utils::Vector params{
         create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
diff --git a/src/tint/writer/glsl/generator_impl_builtin_test.cc b/src/tint/writer/glsl/generator_impl_builtin_test.cc
index 7526494..fa0781b 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_test.cc
@@ -198,25 +198,25 @@
     if (param.type == CallParamType::kF16) {
         Enable(builtin::Extension::kF16);
 
-        GlobalVar("h2", ty.vec2<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("h3", ty.vec3<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("hm2x2", ty.mat2x2<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("hm3x2", ty.mat3x2<f16>(), type::AddressSpace::kPrivate);
+        GlobalVar("h2", ty.vec2<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("h3", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("hm2x2", ty.mat2x2<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("hm3x2", ty.mat3x2<f16>(), builtin::AddressSpace::kPrivate);
     }
 
-    GlobalVar("f2", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("f3", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("u2", ty.vec2<u32>(), type::AddressSpace::kPrivate);
-    GlobalVar("i2", ty.vec2<i32>(), type::AddressSpace::kPrivate);
-    GlobalVar("b2", ty.vec2<bool>(), type::AddressSpace::kPrivate);
-    GlobalVar("m2x2", ty.mat2x2<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("m3x2", ty.mat3x2<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("f2", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("f3", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("u2", ty.vec2<u32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("i2", ty.vec2<i32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b2", ty.vec2<bool>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("m2x2", ty.mat2x2<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("m3x2", ty.mat3x2<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* call = GenerateCall(param.builtin, param.type, this);
     ASSERT_NE(nullptr, call) << "Unhandled builtin";
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(call),
+             Assign(Phony(), call),
          },
          utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
@@ -342,10 +342,10 @@
 TEST_F(GlslGeneratorImplTest_Builtin, Builtin_Call) {
     auto* call = Call("dot", "param1", "param2");
 
-    GlobalVar("param1", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
 
     GeneratorImpl& gen = Build();
 
@@ -356,10 +356,10 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Select_Scalar) {
-    GlobalVar("a", Expr(1_f), type::AddressSpace::kPrivate);
-    GlobalVar("b", Expr(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("a", Expr(1_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", Expr(2_f), builtin::AddressSpace::kPrivate);
     auto* call = Call("select", "a", "b", true);
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
@@ -369,10 +369,10 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Select_Vector) {
-    GlobalVar("a", vec2<i32>(1_i, 2_i), type::AddressSpace::kPrivate);
-    GlobalVar("b", vec2<i32>(3_i, 4_i), type::AddressSpace::kPrivate);
+    GlobalVar("a", vec2<i32>(1_i, 2_i), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", vec2<i32>(3_i, 4_i), builtin::AddressSpace::kPrivate);
     auto* call = Call("select", "a", "b", vec2<bool>(true, false));
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
@@ -384,11 +384,11 @@
 TEST_F(GlslGeneratorImplTest_Builtin, FMA_f32) {
     auto* call = Call("fma", "a", "b", "c");
 
-    GlobalVar("a", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
 
     GeneratorImpl& gen = Build();
 
@@ -401,12 +401,12 @@
 TEST_F(GlslGeneratorImplTest_Builtin, FMA_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.vec3<f16>(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.vec3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("fma", "a", "b", "c");
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
 
     GeneratorImpl& gen = Build();
 
@@ -1226,8 +1226,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack4x8Snorm) {
     auto* call = Call("pack4x8snorm", "p1");
-    GlobalVar("p1", ty.vec4<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1236,7 +1236,7 @@
 vec4 p1 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  packSnorm4x8(p1);
+  uint r = packSnorm4x8(p1);
   return;
 }
 )");
@@ -1244,8 +1244,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack4x8Unorm) {
     auto* call = Call("pack4x8unorm", "p1");
-    GlobalVar("p1", ty.vec4<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1254,7 +1254,7 @@
 vec4 p1 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  packUnorm4x8(p1);
+  uint r = packUnorm4x8(p1);
   return;
 }
 )");
@@ -1262,8 +1262,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Snorm) {
     auto* call = Call("pack2x16snorm", "p1");
-    GlobalVar("p1", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1272,7 +1272,7 @@
 vec2 p1 = vec2(0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  packSnorm2x16(p1);
+  uint r = packSnorm2x16(p1);
   return;
 }
 )");
@@ -1280,8 +1280,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Unorm) {
     auto* call = Call("pack2x16unorm", "p1");
-    GlobalVar("p1", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1290,7 +1290,7 @@
 vec2 p1 = vec2(0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  packUnorm2x16(p1);
+  uint r = packUnorm2x16(p1);
   return;
 }
 )");
@@ -1298,8 +1298,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Float) {
     auto* call = Call("pack2x16float", "p1");
-    GlobalVar("p1", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1308,7 +1308,7 @@
 vec2 p1 = vec2(0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  packHalf2x16(p1);
+  uint r = packHalf2x16(p1);
   return;
 }
 )");
@@ -1316,8 +1316,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack4x8Snorm) {
     auto* call = Call("unpack4x8snorm", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1326,7 +1326,7 @@
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  unpackSnorm4x8(p1);
+  vec4 r = unpackSnorm4x8(p1);
   return;
 }
 )");
@@ -1334,8 +1334,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack4x8Unorm) {
     auto* call = Call("unpack4x8unorm", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1344,7 +1344,7 @@
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  unpackUnorm4x8(p1);
+  vec4 r = unpackUnorm4x8(p1);
   return;
 }
 )");
@@ -1352,8 +1352,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Snorm) {
     auto* call = Call("unpack2x16snorm", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1362,7 +1362,7 @@
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  unpackSnorm2x16(p1);
+  vec2 r = unpackSnorm2x16(p1);
   return;
 }
 )");
@@ -1370,8 +1370,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Unorm) {
     auto* call = Call("unpack2x16unorm", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1380,7 +1380,7 @@
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  unpackUnorm2x16(p1);
+  vec2 r = unpackUnorm2x16(p1);
   return;
 }
 )");
@@ -1388,8 +1388,8 @@
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Float) {
     auto* call = Call("unpack2x16float", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1398,7 +1398,7 @@
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void test_function() {
-  unpackHalf2x16(p1);
+  vec2 r = unpackHalf2x16(p1);
   return;
 }
 )");
@@ -1451,8 +1451,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, DotI32) {
-    GlobalVar("v", ty.vec3<i32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(Call("dot", "v", "v")));
+    GlobalVar("v", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", Call("dot", "v", "v"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -1465,7 +1465,7 @@
 
 ivec3 v = ivec3(0, 0, 0);
 void test_function() {
-  tint_int_dot(v, v);
+  int r = tint_int_dot(v, v);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -1477,8 +1477,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, DotU32) {
-    GlobalVar("v", ty.vec3<u32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(Call("dot", "v", "v")));
+    GlobalVar("v", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", Call("dot", "v", "v"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -1491,7 +1491,7 @@
 
 uvec3 v = uvec3(0u, 0u, 0u);
 void test_function() {
-  tint_int_dot(v, v);
+  uint r = tint_int_dot(v, v);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -1503,7 +1503,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, QuantizeToF16_Scalar) {
-    GlobalVar("v", Expr(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", Expr(2_f), builtin::AddressSpace::kPrivate);
     WrapInFunction(Call("quantizeToF16", "v"));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -1530,7 +1530,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, QuantizeToF16_Vec2) {
-    GlobalVar("v", vec2<f32>(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec2<f32>(2_f), builtin::AddressSpace::kPrivate);
     WrapInFunction(Call("quantizeToF16", "v"));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -1557,7 +1557,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, QuantizeToF16_Vec3) {
-    GlobalVar("v", vec3<f32>(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec3<f32>(2_f), builtin::AddressSpace::kPrivate);
     WrapInFunction(Call("quantizeToF16", "v"));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -1586,7 +1586,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, QuantizeToF16_Vec4) {
-    GlobalVar("v", vec4<f32>(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec4<f32>(2_f), builtin::AddressSpace::kPrivate);
     WrapInFunction(Call("quantizeToF16", "v"));
 
     GeneratorImpl& gen = SanitizeAndBuild();
diff --git a/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc b/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
index be12076..040adfe 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
@@ -254,9 +254,9 @@
         case ValidTextureOverload::kLoadMultisampled2dI32:
             return R"(texelFetch(Texture_1, ivec2(uvec2(1u, 2u)), int(3u));)";
         case ValidTextureOverload::kLoadDepth2dLevelF32:
-            return R"(texelFetch(Texture_1, ivec2(1, 2), 3);)";
+            return R"(texelFetch(Texture_1, ivec2(1, 2), 3).x;)";
         case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
-            return R"(texelFetch(Texture_1, ivec3(uvec3(1u, 2u, 3u)), int(4u));)";
+            return R"(texelFetch(Texture_1, ivec3(uvec3(1u, 2u, 3u)), int(4u)).x;)";
         case ValidTextureOverload::kLoadDepthMultisampled2dF32:
             return R"(texelFetch(Texture_1, ivec2(uvec2(1u, 2u)), int(3u)).x;)";
         case ValidTextureOverload::kStoreWO1dRgba32float:
@@ -281,7 +281,8 @@
     param.BuildSamplerVariable(this);
 
     auto* call = Call(param.function, param.args(this));
-    auto* stmt = CallStmt(call);
+    auto* stmt = param.returns_value ? static_cast<const ast::Statement*>(Decl(Var("v", call)))
+                                     : static_cast<const ast::Statement*>(CallStmt(call));
 
     Func("main", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
diff --git a/src/tint/writer/glsl/generator_impl_call_test.cc b/src/tint/writer/glsl/generator_impl_call_test.cc
index 4ea3790..2f81463 100644
--- a/src/tint/writer/glsl/generator_impl_call_test.cc
+++ b/src/tint/writer/glsl/generator_impl_call_test.cc
@@ -42,8 +42,8 @@
              Param(Sym(), ty.f32()),
          },
          ty.f32(), utils::Vector{Return(1.23_f)});
-    GlobalVar("param1", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("my_func", "param1", "param2");
     WrapInFunction(call);
@@ -62,8 +62,8 @@
              Param(Sym(), ty.f32()),
          },
          ty.void_(), utils::Empty, utils::Empty);
-    GlobalVar("param1", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = CallStmt(Call("my_func", "param1", "param2"));
     WrapInFunction(call);
diff --git a/src/tint/writer/glsl/generator_impl_initializer_test.cc b/src/tint/writer/glsl/generator_impl_constructor_test.cc
similarity index 77%
rename from src/tint/writer/glsl/generator_impl_initializer_test.cc
rename to src/tint/writer/glsl/generator_impl_constructor_test.cc
index d62942d..2f4b3d0 100644
--- a/src/tint/writer/glsl/generator_impl_initializer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_constructor_test.cc
@@ -22,9 +22,9 @@
 
 using ::testing::HasSubstr;
 
-using GlslGeneratorImplTest_Initializer = TestHelper;
+using GlslGeneratorImplTest_Constructor = TestHelper;
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Bool) {
+TEST_F(GlslGeneratorImplTest_Constructor, Bool) {
     WrapInFunction(Expr(false));
 
     GeneratorImpl& gen = Build();
@@ -33,7 +33,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Int) {
+TEST_F(GlslGeneratorImplTest_Constructor, Int) {
     WrapInFunction(Expr(-12345_i));
 
     GeneratorImpl& gen = Build();
@@ -42,7 +42,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_UInt) {
+TEST_F(GlslGeneratorImplTest_Constructor, UInt) {
     WrapInFunction(Expr(56779_u));
 
     GeneratorImpl& gen = Build();
@@ -51,7 +51,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Float) {
+TEST_F(GlslGeneratorImplTest_Constructor, Float) {
     // Use a number close to 1<<30 but whose decimal representation ends in 0.
     WrapInFunction(Expr(f32((1 << 30) - 4)));
 
@@ -61,7 +61,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_F16) {
+TEST_F(GlslGeneratorImplTest_Constructor, F16) {
     Enable(builtin::Extension::kF16);
 
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
@@ -73,7 +73,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("32752.0hf"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Float) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Float) {
     WrapInFunction(Call<f32>(-1.2e-5_f));
 
     GeneratorImpl& gen = Build();
@@ -82,7 +82,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-0.000012f"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_F16) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(Call<f16>(-1.2e-3_h));
@@ -93,7 +93,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-0.00119972229hf"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Bool) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Bool) {
     WrapInFunction(Call<bool>(true));
 
     GeneratorImpl& gen = Build();
@@ -102,7 +102,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("true"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Int) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Int) {
     WrapInFunction(Call<i32>(-12345_i));
 
     GeneratorImpl& gen = Build();
@@ -111,7 +111,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Uint) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Uint) {
     WrapInFunction(Call<u32>(12345_u));
 
     GeneratorImpl& gen = Build();
@@ -120,7 +120,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("12345u"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_F32) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_F32) {
     WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
 
     GeneratorImpl& gen = Build();
@@ -129,7 +129,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("vec3(1.0f, 2.0f, 3.0f)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_F16) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
@@ -140,7 +140,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("f16vec3(1.0hf, 2.0hf, 3.0hf)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_Empty_F32) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_Empty_F32) {
     WrapInFunction(vec3<f32>());
 
     GeneratorImpl& gen = Build();
@@ -149,7 +149,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("vec3(0.0f)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_Empty_F16) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>());
@@ -160,7 +160,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("f16vec3(0.0hf)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F32_Literal) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Literal) {
     WrapInFunction(vec3<f32>(2_f));
 
     GeneratorImpl& gen = Build();
@@ -169,7 +169,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("vec3(2.0f)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F16_Literal) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Literal) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(2_h));
@@ -180,7 +180,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("f16vec3(2.0hf)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F32_Var) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Var) {
     auto* var = Var("v", Expr(2_f));
     auto* cast = vec3<f32>(var);
     WrapInFunction(var, cast);
@@ -192,7 +192,7 @@
   vec3 tint_symbol = vec3(v);)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F16_Var) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Var) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
@@ -206,7 +206,7 @@
   f16vec3 tint_symbol = f16vec3(v);)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_Bool) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Bool) {
     WrapInFunction(vec3<bool>(true));
 
     GeneratorImpl& gen = Build();
@@ -215,7 +215,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("bvec3(true)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_Int) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Int) {
     WrapInFunction(vec3<i32>(2_i));
 
     GeneratorImpl& gen = Build();
@@ -224,7 +224,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("ivec3(2)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_UInt) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_UInt) {
     WrapInFunction(vec3<u32>(2_u));
 
     GeneratorImpl& gen = Build();
@@ -233,7 +233,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("uvec3(2u)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_F32) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_F32) {
     WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
 
     GeneratorImpl& gen = Build();
@@ -243,7 +243,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(3.0f, 4.0f, 5.0f))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_F16) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
@@ -256,7 +256,7 @@
                 HasSubstr("f16mat2x3(f16vec3(1.0hf, 2.0hf, 3.0hf), f16vec3(3.0hf, 4.0hf, 5.0hf))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Complex_F32) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_Complex_F32) {
     // mat4x4<f32>(
     //     vec4<f32>(2.0f, 3.0f, 4.0f, 8.0f),
     //     vec4<f32>(),
@@ -270,10 +270,10 @@
     auto* vector_identical_init =
         vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
 
-    auto* initializer = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
-                                    vector_identical_init);
+    auto* ctor = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
+                             vector_identical_init);
 
-    WrapInFunction(initializer);
+    WrapInFunction(ctor);
 
     GeneratorImpl& gen = Build();
 
@@ -283,7 +283,7 @@
                                         "vec4(7.0f), vec4(42.0f, 21.0f, 6.0f, -5.0f))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Complex_F16) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_Complex_F16) {
     // mat4x4<f16>(
     //     vec4<f16>(2.0h, 3.0h, 4.0h, 8.0h),
     //     vec4<f16>(),
@@ -299,10 +299,10 @@
     auto* vector_identical_init =
         vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
 
-    auto* initializer = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
-                                    vector_identical_init);
+    auto* ctor = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
+                             vector_identical_init);
 
-    WrapInFunction(initializer);
+    WrapInFunction(ctor);
 
     GeneratorImpl& gen = Build();
 
@@ -313,7 +313,7 @@
                           "f16vec4(7.0hf), f16vec4(42.0hf, 21.0hf, 6.0hf, -5.0hf))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Empty_F32) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_Empty_F32) {
     WrapInFunction(mat2x3<f32>());
 
     GeneratorImpl& gen = Build();
@@ -323,7 +323,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("mat2x3 tint_symbol = mat2x3(vec3(0.0f), vec3(0.0f))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Empty_F16) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>());
@@ -336,7 +336,7 @@
                 HasSubstr("f16mat2x3 tint_symbol = f16mat2x3(f16vec3(0.0hf), f16vec3(0.0hf))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Identity_F32) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_Identity_F32) {
     // fn f() {
     //     var m_1: mat4x4<f32> = mat4x4<f32>();
     //     var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
@@ -354,7 +354,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("mat4 m_2 = mat4(m_1);"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Identity_F16) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_Identity_F16) {
     // fn f() {
     //     var m_1: mat4x4<f16> = mat4x4<f16>();
     //     var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
@@ -374,7 +374,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("f16mat4 m_2 = f16mat4(m_1);"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Array) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Array) {
     WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
                         vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
 
@@ -386,7 +386,7 @@
                                         "vec3(7.0f, 8.0f, 9.0f))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Array_Empty) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Array_Empty) {
     WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u)));
 
     GeneratorImpl& gen = Build();
@@ -395,7 +395,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("vec3[3](vec3(0.0f), vec3(0.0f), vec3(0.0f))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Struct) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Struct) {
     auto* str = Structure("S", utils::Vector{
                                    Member("a", ty.i32()),
                                    Member("b", ty.f32()),
@@ -410,7 +410,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("S(1, 2.0f, ivec3(3, 4, 5))"));
 }
 
-TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Struct_Empty) {
+TEST_F(GlslGeneratorImplTest_Constructor, Type_Struct_Empty) {
     auto* str = Structure("S", utils::Vector{
                                    Member("a", ty.i32()),
                                    Member("b", ty.f32()),
diff --git a/src/tint/writer/glsl/generator_impl_function_test.cc b/src/tint/writer/glsl/generator_impl_function_test.cc
index 2d1ed02..05d1460 100644
--- a/src/tint/writer/glsl/generator_impl_function_test.cc
+++ b/src/tint/writer/glsl/generator_impl_function_test.cc
@@ -110,8 +110,8 @@
     // fn f(foo : ptr<function, f32>) -> f32 {
     //   return *foo;
     // }
-    Func("f", utils::Vector{Param("foo", ty.pointer<f32>(type::AddressSpace::kFunction))}, ty.f32(),
-         utils::Vector{Return(Deref("foo"))});
+    Func("f", utils::Vector{Param("foo", ty.pointer<f32>(builtin::AddressSpace::kFunction))},
+         ty.f32(), utils::Vector{Return(Deref("foo"))});
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -352,7 +352,7 @@
 TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_Uniform) {
     auto* ubo_ty = Structure("UBO", utils::Vector{Member("coord", ty.vec4<f32>())});
     auto* ubo =
-        GlobalVar("ubo", ty.Of(ubo_ty), type::AddressSpace::kUniform, Binding(0_a), Group(1_a));
+        GlobalVar("ubo", ty.Of(ubo_ty), builtin::AddressSpace::kUniform, Binding(0_a), Group(1_a));
 
     Func("sub_func",
          utils::Vector{
@@ -402,7 +402,7 @@
 TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_UniformStruct) {
     auto* s = Structure("Uniforms", utils::Vector{Member("coord", ty.vec4<f32>())});
 
-    GlobalVar("uniforms", ty.Of(s), type::AddressSpace::kUniform, Binding(0_a), Group(1_a));
+    GlobalVar("uniforms", ty.Of(s), builtin::AddressSpace::kUniform, Binding(0_a), Group(1_a));
 
     auto* var = Var("v", ty.f32(), MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
 
@@ -442,7 +442,7 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(1_a));
 
     auto* var = Var("v", ty.f32(), MemberAccessor("coord", "b"));
@@ -489,8 +489,8 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
-              Group(1_a));
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead,
+              Binding(0_a), Group(1_a));
 
     auto* var = Var("v", ty.f32(), MemberAccessor("coord", "b"));
 
@@ -537,7 +537,7 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(1_a));
 
     Func("frag_main", utils::Empty, ty.void_(),
@@ -582,7 +582,7 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(1_a));
 
     Func("frag_main", utils::Empty, ty.void_(),
@@ -623,7 +623,7 @@
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
     auto* s = Structure("S", utils::Vector{Member("x", ty.f32())});
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kUniform, Binding(0_a), Group(1_a));
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kUniform, Binding(0_a), Group(1_a));
 
     Func("sub_func", utils::Vector{Param("param", ty.f32())}, ty.f32(),
          utils::Vector{
@@ -668,7 +668,7 @@
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
     auto* s = Structure("S", utils::Vector{Member("x", ty.f32())});
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(1_a));
 
     Func("sub_func", utils::Vector{Param("param", ty.f32())}, ty.f32(),
@@ -879,7 +879,7 @@
 
     auto* s = Structure("Data", utils::Vector{Member("d", ty.f32())});
 
-    GlobalVar("data", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("data", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(0_a));
 
     {
diff --git a/src/tint/writer/glsl/generator_impl_identifier_test.cc b/src/tint/writer/glsl/generator_impl_identifier_test.cc
index 7e528ac..cd0b109 100644
--- a/src/tint/writer/glsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/glsl/generator_impl_identifier_test.cc
@@ -20,7 +20,7 @@
 using GlslGeneratorImplTest_Identifier = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Identifier, EmitIdentifierExpression) {
-    GlobalVar("foo", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("foo", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* i = Expr("foo");
     WrapInFunction(i);
diff --git a/src/tint/writer/glsl/generator_impl_if_test.cc b/src/tint/writer/glsl/generator_impl_if_test.cc
index a0957e1..0713ab7 100644
--- a/src/tint/writer/glsl/generator_impl_if_test.cc
+++ b/src/tint/writer/glsl/generator_impl_if_test.cc
@@ -20,7 +20,7 @@
 using GlslGeneratorImplTest_If = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_If, Emit_If) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* cond = Expr("cond");
     auto* body = Block(Return());
@@ -38,8 +38,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_If, Emit_IfWithElseIf) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("else_cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("else_cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_cond = Expr("else_cond");
     auto* else_body = Block(Return());
@@ -65,7 +65,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_If, Emit_IfWithElse) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_body = Block(Return());
 
@@ -88,8 +88,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_If, Emit_IfWithMultiple) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("else_cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("else_cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_cond = Expr("else_cond");
 
diff --git a/src/tint/writer/glsl/generator_impl_import_test.cc b/src/tint/writer/glsl/generator_impl_import_test.cc
index adfebe4..10da8aa 100644
--- a/src/tint/writer/glsl/generator_impl_import_test.cc
+++ b/src/tint/writer/glsl/generator_impl_import_test.cc
@@ -251,7 +251,7 @@
                          testing::Values(GlslImportData{"clamp", "clamp"}));
 
 TEST_F(GlslGeneratorImplTest_Import, GlslImportData_Determinant) {
-    GlobalVar("var", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("determinant", "var");
     WrapInFunction(expr);
diff --git a/src/tint/writer/glsl/generator_impl_loop_test.cc b/src/tint/writer/glsl/generator_impl_loop_test.cc
index 79374a2..0979f53 100644
--- a/src/tint/writer/glsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/glsl/generator_impl_loop_test.cc
@@ -93,8 +93,8 @@
 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopNestedWithContinuing) {
     Func("a_statement", {}, ty.void_(), {});
 
-    GlobalVar("lhs", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("rhs", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("lhs", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
@@ -142,7 +142,7 @@
     //   }
     // }
 
-    GlobalVar("rhs", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4_f))),  //
                        Decl(Var("other", ty.f32())),             //
diff --git a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
index 1023ad0..e551c75 100644
--- a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
@@ -91,8 +91,8 @@
 
         auto* s = b.Structure("Data", members);
 
-        b.GlobalVar("data", b.ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
-                    b.Group(1_a), b.Binding(0_a));
+        b.GlobalVar("data", b.ty.Of(s), builtin::AddressSpace::kStorage,
+                    builtin::Access::kReadWrite, b.Group(1_a), b.Binding(0_a));
     }
 
     void SetupFunction(utils::VectorRef<const ast::Statement*> statements) {
@@ -112,7 +112,7 @@
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
     auto* s = Structure("Data", utils::Vector{Member("mem", ty.f32())});
-    GlobalVar("str", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("str", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     auto* expr = MemberAccessor("str", "mem");
     WrapInFunction(Var("expr", ty.f32(), expr));
diff --git a/src/tint/writer/glsl/generator_impl_sanitizer_test.cc b/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
index 051d8e0..e85d050 100644
--- a/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
@@ -26,7 +26,7 @@
 
 TEST_F(GlslSanitizerTest, Call_ArrayLength) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
@@ -66,7 +66,7 @@
                                          Member(0, "z", ty.f32()),
                                          Member(4, "a", ty.array<f32>()),
                                      });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
@@ -105,7 +105,7 @@
 
 TEST_F(GlslSanitizerTest, Call_ArrayLength_ViaLets) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     auto* p = Let("p", AddressOf("b"));
@@ -233,7 +233,7 @@
     // let p : ptr<function, i32> = &v;
     // let x : i32 = *p;
     auto* v = Var("v", ty.i32());
-    auto* p = Let("p", ty.pointer<i32>(type::AddressSpace::kFunction), AddressOf(v));
+    auto* p = Let("p", ty.pointer<i32>(builtin::AddressSpace::kFunction), AddressOf(v));
     auto* x = Var("x", ty.i32(), Deref(p));
 
     Func("main", utils::Empty, ty.void_(),
@@ -274,11 +274,12 @@
     // let vp : ptr<function, vec4<f32>> = &(*mp)[2i];
     // let v : vec4<f32> = *vp;
     auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4_u));
-    auto* ap = Let("ap", ty.pointer(ty.array(ty.mat4x4<f32>(), 4_u), type::AddressSpace::kFunction),
-                   AddressOf(a));
-    auto* mp = Let("mp", ty.pointer(ty.mat4x4<f32>(), type::AddressSpace::kFunction),
+    auto* ap =
+        Let("ap", ty.pointer(ty.array(ty.mat4x4<f32>(), 4_u), builtin::AddressSpace::kFunction),
+            AddressOf(a));
+    auto* mp = Let("mp", ty.pointer(ty.mat4x4<f32>(), builtin::AddressSpace::kFunction),
                    AddressOf(IndexAccessor(Deref(ap), 3_i)));
-    auto* vp = Let("vp", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kFunction),
+    auto* vp = Let("vp", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kFunction),
                    AddressOf(IndexAccessor(Deref(mp), 2_i)));
     auto* v = Var("v", ty.vec4<f32>(), Deref(vp));
 
diff --git a/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc b/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
index 3572da4..7513e94 100644
--- a/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
@@ -37,8 +37,8 @@
                        ctx->Member("dewey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_i)}),
                        ctx->Member("louie", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_i)}),
                    });
-    ctx->GlobalVar("nephews", ctx->ty.Of(nephews), type::AddressSpace::kStorage, ctx->Binding(0_a),
-                   ctx->Group(0_a));
+    ctx->GlobalVar("nephews", ctx->ty.Of(nephews), builtin::AddressSpace::kStorage,
+                   ctx->Binding(0_a), ctx->Group(0_a));
 }
 
 TEST_F(GlslGeneratorImplTest_StorageBuffer, Align) {
diff --git a/src/tint/writer/glsl/generator_impl_switch_test.cc b/src/tint/writer/glsl/generator_impl_switch_test.cc
index 2f90c8f..b9ff49d 100644
--- a/src/tint/writer/glsl/generator_impl_switch_test.cc
+++ b/src/tint/writer/glsl/generator_impl_switch_test.cc
@@ -22,7 +22,7 @@
 using GlslGeneratorImplTest_Switch = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Switch, Emit_Switch) {
-    GlobalVar("cond", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* def_body = Block(create<ast::BreakStatement>());
     auto* def = create<ast::CaseStatement>(utils::Vector{DefaultCaseSelector()}, def_body);
@@ -51,7 +51,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Switch, Emit_Switch_MixedDefault) {
-    GlobalVar("cond", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* def_body = Block(create<ast::BreakStatement>());
     auto* def = create<ast::CaseStatement>(utils::Vector{CaseSelector(5_i), DefaultCaseSelector()},
diff --git a/src/tint/writer/glsl/generator_impl_test.cc b/src/tint/writer/glsl/generator_impl_test.cc
index b449253..9a24471 100644
--- a/src/tint/writer/glsl/generator_impl_test.cc
+++ b/src/tint/writer/glsl/generator_impl_test.cc
@@ -62,7 +62,7 @@
                   Builtin(builtin::BuiltinValue::kSampleIndex),
                   Disable(ast::DisabledValidation::kIgnoreAddressSpace),
               },
-              type::AddressSpace::kIn);
+              builtin::AddressSpace::kIn);
     Func("my_func", utils::Empty, ty.i32(),
          utils::Vector{
              Return(Expr("gl_SampleID")),
@@ -87,7 +87,7 @@
                   Builtin(builtin::BuiltinValue::kSampleIndex),
                   Disable(ast::DisabledValidation::kIgnoreAddressSpace),
               },
-              type::AddressSpace::kIn);
+              builtin::AddressSpace::kIn);
     Func("my_func", utils::Empty, ty.i32(),
          utils::Vector{
              Return(Expr("gl_SampleID")),
diff --git a/src/tint/writer/glsl/generator_impl_type_test.cc b/src/tint/writer/glsl/generator_impl_type_test.cc
index b538979..492910d 100644
--- a/src/tint/writer/glsl/generator_impl_type_test.cc
+++ b/src/tint/writer/glsl/generator_impl_type_test.cc
@@ -34,52 +34,52 @@
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Array) {
     auto arr = ty.array<bool, 4>();
-    ast::Type ty = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, "ary"))
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, "ary"))
         << gen.error();
     EXPECT_EQ(out.str(), "bool ary[4]");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
     auto arr = ty.array(ty.array<bool, 4>(), 5_u);
-    ast::Type ty = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, "ary"))
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, "ary"))
         << gen.error();
     EXPECT_EQ(out.str(), "bool ary[5][4]");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
     auto arr = ty.array(ty.array(ty.array<bool, 4>(), 5_u), 6_u);
-    ast::Type ty = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, "ary"))
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, "ary"))
         << gen.error();
     EXPECT_EQ(out.str(), "bool ary[6][5][4]");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Array_WithoutName) {
     auto arr = ty.array<bool, 4>();
-    ast::Type ty = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "bool[4]");
 }
@@ -90,7 +90,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, bool_, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, bool_, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "bool");
 }
@@ -101,7 +102,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, f32, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, f32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "float");
 }
@@ -114,7 +116,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, f16, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, f16, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "float16_t");
 }
@@ -125,7 +128,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, i32, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, i32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "int");
 }
@@ -138,7 +142,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, mat2x3, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "mat2x3");
 }
@@ -153,7 +158,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, mat2x3, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "f16mat2x3");
 }
@@ -163,7 +169,7 @@
                                  Member("a", ty.i32()),
                                  Member("b", ty.f32()),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
@@ -183,13 +189,14 @@
                                  Member("a", ty.i32()),
                                  Member("b", ty.f32()),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
     auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, sem_s, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, sem_s, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "S");
 }
@@ -199,7 +206,7 @@
                                  Member("double", ty.i32()),
                                  Member("float", ty.f32()),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -216,7 +223,7 @@
                                  Member("a", ty.i32(), utils::Vector{MemberOffset(0_a)}),
                                  Member("b", ty.f32(), utils::Vector{MemberOffset(8_a)}),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
@@ -237,7 +244,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, u32, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, u32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "uint");
 }
@@ -249,7 +257,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, vec3, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, vec3, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "vec3");
 }
@@ -263,7 +272,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, vec3, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, vec3, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "f16vec3");
 }
@@ -274,7 +284,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, void_, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, void_, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "void");
 }
@@ -285,8 +296,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_FALSE(
-        gen.EmitType(out, sampler, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_FALSE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
+                              builtin::Access::kReadWrite, ""))
         << gen.error();
 }
 
@@ -296,8 +307,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_FALSE(
-        gen.EmitType(out, sampler, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_FALSE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
+                              builtin::Access::kReadWrite, ""))
         << gen.error();
 }
 
@@ -319,7 +330,7 @@
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Decl(Var("v", Call("textureDimensions", "tex"))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -347,7 +358,7 @@
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Decl(Var("v", Call("textureDimensions", "tex"))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -391,7 +402,7 @@
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Decl(Var("v", Call("textureDimensions", "tex"))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -503,14 +514,15 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, s, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, s, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "highp sampler2DMS");
 }
 
 struct GlslStorageTextureData {
     type::TextureDimension dim;
-    type::TexelFormat imgfmt;
+    builtin::TexelFormat imgfmt;
     std::string result;
 };
 inline std::ostream& operator<<(std::ostream& out, GlslStorageTextureData data) {
@@ -520,13 +532,13 @@
 TEST_P(GlslStorageTexturesTest, Emit) {
     auto params = GetParam();
 
-    auto t = ty.storage_texture(params.dim, params.imgfmt, type::Access::kWrite);
+    auto t = ty.storage_texture(params.dim, params.imgfmt, builtin::Access::kWrite);
 
     GlobalVar("tex", t, Binding(1_a), Group(2_a));
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Decl(Var("v", Call("textureDimensions", "tex"))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -541,31 +553,31 @@
     GlslGeneratorImplTest_Type,
     GlslStorageTexturesTest,
     testing::Values(GlslStorageTextureData{type::TextureDimension::k1d,
-                                           type::TexelFormat::kRgba8Unorm, "image1D tex;"},
+                                           builtin::TexelFormat::kRgba8Unorm, "image1D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k2d,
-                                           type::TexelFormat::kRgba16Float, "image2D tex;"},
+                                           builtin::TexelFormat::kRgba16Float, "image2D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k2dArray,
-                                           type::TexelFormat::kR32Float, "image2DArray tex;"},
+                                           builtin::TexelFormat::kR32Float, "image2DArray tex;"},
                     GlslStorageTextureData{type::TextureDimension::k3d,
-                                           type::TexelFormat::kRg32Float, "image3D tex;"},
+                                           builtin::TexelFormat::kRg32Float, "image3D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k1d,
-                                           type::TexelFormat::kRgba32Float, "image1D tex;"},
+                                           builtin::TexelFormat::kRgba32Float, "image1D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k2d,
-                                           type::TexelFormat::kRgba16Uint, "image2D tex;"},
+                                           builtin::TexelFormat::kRgba16Uint, "image2D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k2dArray,
-                                           type::TexelFormat::kR32Uint, "image2DArray tex;"},
+                                           builtin::TexelFormat::kR32Uint, "image2DArray tex;"},
                     GlslStorageTextureData{type::TextureDimension::k3d,
-                                           type::TexelFormat::kRg32Uint, "image3D tex;"},
+                                           builtin::TexelFormat::kRg32Uint, "image3D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k1d,
-                                           type::TexelFormat::kRgba32Uint, "image1D tex;"},
+                                           builtin::TexelFormat::kRgba32Uint, "image1D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k2d,
-                                           type::TexelFormat::kRgba16Sint, "image2D tex;"},
+                                           builtin::TexelFormat::kRgba16Sint, "image2D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k2dArray,
-                                           type::TexelFormat::kR32Sint, "image2DArray tex;"},
+                                           builtin::TexelFormat::kR32Sint, "image2DArray tex;"},
                     GlslStorageTextureData{type::TextureDimension::k3d,
-                                           type::TexelFormat::kRg32Sint, "image3D tex;"},
+                                           builtin::TexelFormat::kRg32Sint, "image3D tex;"},
                     GlslStorageTextureData{type::TextureDimension::k1d,
-                                           type::TexelFormat::kRgba32Sint, "image1D tex;"}));
+                                           builtin::TexelFormat::kRgba32Sint, "image1D tex;"}));
 
 }  // namespace
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/glsl/generator_impl_unary_op_test.cc b/src/tint/writer/glsl/generator_impl_unary_op_test.cc
index c0eb7b1..18f180e 100644
--- a/src/tint/writer/glsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/glsl/generator_impl_unary_op_test.cc
@@ -20,7 +20,7 @@
 using GlslUnaryOpTest = TestHelper;
 
 TEST_F(GlslUnaryOpTest, AddressOf) {
-    GlobalVar("expr", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
     WrapInFunction(op);
 
@@ -32,7 +32,7 @@
 }
 
 TEST_F(GlslUnaryOpTest, Complement) {
-    GlobalVar("expr", ty.u32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.u32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
     WrapInFunction(op);
 
@@ -44,7 +44,7 @@
 }
 
 TEST_F(GlslUnaryOpTest, Indirection) {
-    GlobalVar("G", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("G", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* p = Let("expr", create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
     WrapInFunction(p, op);
@@ -57,7 +57,7 @@
 }
 
 TEST_F(GlslUnaryOpTest, Not) {
-    GlobalVar("expr", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.bool_(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
     WrapInFunction(op);
 
@@ -69,7 +69,7 @@
 }
 
 TEST_F(GlslUnaryOpTest, Negation) {
-    GlobalVar("expr", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
     WrapInFunction(op);
 
diff --git a/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc b/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
index 48f635a..2ace33c 100644
--- a/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
@@ -26,7 +26,7 @@
 
 TEST_F(GlslGeneratorImplTest_UniformBuffer, Simple) {
     auto* simple = Structure("Simple", utils::Vector{Member("member", ty.f32())});
-    GlobalVar("simple", ty.Of(simple), type::AddressSpace::kUniform, Group(0_a), Binding(0_a));
+    GlobalVar("simple", ty.Of(simple), builtin::AddressSpace::kUniform, Group(0_a), Binding(0_a));
 
     GeneratorImpl& gen = Build();
 
@@ -46,7 +46,7 @@
 
 TEST_F(GlslGeneratorImplTest_UniformBuffer, Simple_Desktop) {
     auto* simple = Structure("Simple", utils::Vector{Member("member", ty.f32())});
-    GlobalVar("simple", ty.Of(simple), type::AddressSpace::kUniform, Group(0_a), Binding(0_a));
+    GlobalVar("simple", ty.Of(simple), builtin::AddressSpace::kUniform, Group(0_a), Binding(0_a));
 
     GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
 
diff --git a/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
index a4d11cb..5691312 100644
--- a/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
@@ -475,7 +475,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
 
     WrapInFunction(Expr("a"));
 
diff --git a/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc b/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
index 97f8cf8..676025c 100644
--- a/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
+++ b/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
@@ -27,7 +27,7 @@
 using GlslGeneratorImplTest_WorkgroupVar = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_WorkgroupVar, Basic) {
-    GlobalVar("wg", ty.f32(), type::AddressSpace::kWorkgroup);
+    GlobalVar("wg", ty.f32(), builtin::AddressSpace::kWorkgroup);
 
     Func("main", utils::Empty, ty.void_(), utils::Vector{Assign("wg", 1.2_f)},
          utils::Vector{
@@ -43,7 +43,7 @@
 TEST_F(GlslGeneratorImplTest_WorkgroupVar, Aliased) {
     auto* alias = Alias("F32", ty.f32());
 
-    GlobalVar("wg", ty.Of(alias), type::AddressSpace::kWorkgroup);
+    GlobalVar("wg", ty.Of(alias), builtin::AddressSpace::kWorkgroup);
 
     Func("main", utils::Empty, ty.void_(), utils::Vector{Assign("wg", 1.2_f)},
          utils::Vector{
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index aab30d2..787962b 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -37,8 +37,8 @@
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/switch_statement.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/transform/add_empty_entry_point.h"
 #include "src/tint/transform/array_length_from_uniform.h"
@@ -87,27 +87,27 @@
 
 const char kTempNamePrefix[] = "tint_tmp";
 
-const char* image_format_to_rwtexture_type(type::TexelFormat image_format) {
+const char* image_format_to_rwtexture_type(builtin::TexelFormat image_format) {
     switch (image_format) {
-        case type::TexelFormat::kBgra8Unorm:
-        case type::TexelFormat::kRgba8Unorm:
-        case type::TexelFormat::kRgba8Snorm:
-        case type::TexelFormat::kRgba16Float:
-        case type::TexelFormat::kR32Float:
-        case type::TexelFormat::kRg32Float:
-        case type::TexelFormat::kRgba32Float:
+        case builtin::TexelFormat::kBgra8Unorm:
+        case builtin::TexelFormat::kRgba8Unorm:
+        case builtin::TexelFormat::kRgba8Snorm:
+        case builtin::TexelFormat::kRgba16Float:
+        case builtin::TexelFormat::kR32Float:
+        case builtin::TexelFormat::kRg32Float:
+        case builtin::TexelFormat::kRgba32Float:
             return "float4";
-        case type::TexelFormat::kRgba8Uint:
-        case type::TexelFormat::kRgba16Uint:
-        case type::TexelFormat::kR32Uint:
-        case type::TexelFormat::kRg32Uint:
-        case type::TexelFormat::kRgba32Uint:
+        case builtin::TexelFormat::kRgba8Uint:
+        case builtin::TexelFormat::kRgba16Uint:
+        case builtin::TexelFormat::kR32Uint:
+        case builtin::TexelFormat::kRg32Uint:
+        case builtin::TexelFormat::kRgba32Uint:
             return "uint4";
-        case type::TexelFormat::kRgba8Sint:
-        case type::TexelFormat::kRgba16Sint:
-        case type::TexelFormat::kR32Sint:
-        case type::TexelFormat::kRg32Sint:
-        case type::TexelFormat::kRgba32Sint:
+        case builtin::TexelFormat::kRgba8Sint:
+        case builtin::TexelFormat::kRgba16Sint:
+        case builtin::TexelFormat::kR32Sint:
+        case builtin::TexelFormat::kRg32Sint:
+        case builtin::TexelFormat::kRgba32Sint:
             return "int4";
         default:
             return nullptr;
@@ -335,8 +335,8 @@
                 auto* ty = builder_.Sem().Get(str);
                 auto address_space_uses = ty->AddressSpaceUsage();
                 if (address_space_uses.size() !=
-                    (address_space_uses.count(type::AddressSpace::kStorage) +
-                     address_space_uses.count(type::AddressSpace::kUniform))) {
+                    (address_space_uses.count(builtin::AddressSpace::kStorage) +
+                     address_space_uses.count(builtin::AddressSpace::kUniform))) {
                     // The structure is used as something other than a storage buffer or
                     // uniform buffer, so it needs to be emitted.
                     // Storage buffer are read and written to via a ByteAddressBuffer
@@ -377,8 +377,8 @@
         std::string fn;
         {
             std::ostringstream ss;
-            if (!EmitType(ss, vec, tint::type::AddressSpace::kUndefined, type::Access::kUndefined,
-                          "")) {
+            if (!EmitType(ss, vec, tint::builtin::AddressSpace::kUndefined,
+                          builtin::Access::kUndefined, "")) {
                 return "";
             }
             fn = UniqueIdentifier("set_" + ss.str());
@@ -386,13 +386,13 @@
         {
             auto out = line(&helpers_);
             out << "void " << fn << "(inout ";
-            if (!EmitTypeAndName(out, vec, type::AddressSpace::kUndefined, type::Access::kUndefined,
-                                 "vec")) {
+            if (!EmitTypeAndName(out, vec, builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, "vec")) {
                 return "";
             }
             out << ", int idx, ";
-            if (!EmitTypeAndName(out, vec->type(), type::AddressSpace::kUndefined,
-                                 type::Access::kUndefined, "val")) {
+            if (!EmitTypeAndName(out, vec->type(), builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, "val")) {
                 return "";
             }
             out << ") {";
@@ -451,8 +451,8 @@
         std::string fn;
         {
             std::ostringstream ss;
-            if (!EmitType(ss, mat, tint::type::AddressSpace::kUndefined, type::Access::kUndefined,
-                          "")) {
+            if (!EmitType(ss, mat, tint::builtin::AddressSpace::kUndefined,
+                          builtin::Access::kUndefined, "")) {
                 return "";
             }
             fn = UniqueIdentifier("set_vector_" + ss.str());
@@ -460,13 +460,13 @@
         {
             auto out = line(&helpers_);
             out << "void " << fn << "(inout ";
-            if (!EmitTypeAndName(out, mat, type::AddressSpace::kUndefined, type::Access::kUndefined,
-                                 "mat")) {
+            if (!EmitTypeAndName(out, mat, builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, "mat")) {
                 return "";
             }
             out << ", int col, ";
-            if (!EmitTypeAndName(out, mat->ColumnType(), type::AddressSpace::kUndefined,
-                                 type::Access::kUndefined, "val")) {
+            if (!EmitTypeAndName(out, mat->ColumnType(), builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, "val")) {
                 return "";
             }
             out << ") {";
@@ -520,8 +520,8 @@
         std::string fn;
         {
             std::ostringstream ss;
-            if (!EmitType(ss, mat, tint::type::AddressSpace::kUndefined, type::Access::kUndefined,
-                          "")) {
+            if (!EmitType(ss, mat, tint::builtin::AddressSpace::kUndefined,
+                          builtin::Access::kUndefined, "")) {
                 return "";
             }
             fn = UniqueIdentifier("set_scalar_" + ss.str());
@@ -529,13 +529,13 @@
         {
             auto out = line(&helpers_);
             out << "void " << fn << "(inout ";
-            if (!EmitTypeAndName(out, mat, type::AddressSpace::kUndefined, type::Access::kUndefined,
-                                 "mat")) {
+            if (!EmitTypeAndName(out, mat, builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, "mat")) {
                 return "";
             }
             out << ", int col, int row, ";
-            if (!EmitTypeAndName(out, mat->type(), type::AddressSpace::kUndefined,
-                                 type::Access::kUndefined, "val")) {
+            if (!EmitTypeAndName(out, mat->type(), builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, "val")) {
                 return "";
             }
             out << ") {";
@@ -642,7 +642,7 @@
     }
 
     out << "as";
-    if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+    if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, "")) {
         return false;
     }
     out << "(";
@@ -876,10 +876,11 @@
     auto* call = builder_.Sem().Get<sem::Call>(expr);
     auto* target = call->Target();
     return Switch(
-        target, [&](const sem::Function* func) { return EmitFunctionCall(out, call, func); },
+        target,  //
+        [&](const sem::Function* func) { return EmitFunctionCall(out, call, func); },
         [&](const sem::Builtin* builtin) { return EmitBuiltinCall(out, call, builtin); },
-        [&](const sem::TypeConversion* conv) { return EmitTypeConversion(out, call, conv); },
-        [&](const sem::TypeInitializer* ctor) { return EmitTypeInitializer(out, call, ctor); },
+        [&](const sem::ValueConversion* conv) { return EmitValueConversion(out, call, conv); },
+        [&](const sem::ValueConstructor* ctor) { return EmitValueConstructor(out, call, ctor); },
         [&](Default) {
             TINT_ICE(Writer, diagnostics_) << "unhandled call target: " << target->TypeInfo().name;
             return false;
@@ -909,9 +910,9 @@
     if (auto* intrinsic = ast::GetAttribute<transform::DecomposeMemoryAccess::Intrinsic>(
             func->Declaration()->attributes)) {
         switch (intrinsic->address_space) {
-            case type::AddressSpace::kUniform:
+            case builtin::AddressSpace::kUniform:
                 return EmitUniformBufferAccess(out, expr, intrinsic);
-            case type::AddressSpace::kStorage:
+            case builtin::AddressSpace::kStorage:
                 if (!intrinsic->IsAtomic()) {
                     return EmitStorageBufferAccess(out, expr, intrinsic);
                 }
@@ -1027,10 +1028,11 @@
     return true;
 }
 
-bool GeneratorImpl::EmitTypeConversion(std::ostream& out,
-                                       const sem::Call* call,
-                                       const sem::TypeConversion* conv) {
-    if (!EmitType(out, conv->Target(), type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+bool GeneratorImpl::EmitValueConversion(std::ostream& out,
+                                        const sem::Call* call,
+                                        const sem::ValueConversion* conv) {
+    if (!EmitType(out, conv->Target(), builtin::AddressSpace::kUndefined,
+                  builtin::Access::kReadWrite, "")) {
         return false;
     }
     out << "(";
@@ -1043,13 +1045,13 @@
     return true;
 }
 
-bool GeneratorImpl::EmitTypeInitializer(std::ostream& out,
-                                        const sem::Call* call,
-                                        const sem::TypeInitializer* ctor) {
+bool GeneratorImpl::EmitValueConstructor(std::ostream& out,
+                                         const sem::Call* call,
+                                         const sem::ValueConstructor* ctor) {
     auto* type = call->Type();
 
-    // If the type initializer is empty then we need to construct with the zero
-    // value for all components.
+    // If the value constructor arguments are empty then we need to construct with the zero value
+    // for all components.
     if (call->Arguments().IsEmpty()) {
         return EmitZeroValue(out, type);
     }
@@ -1075,7 +1077,8 @@
     if (brackets) {
         out << "{";
     } else {
-        if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+        if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                      "")) {
             return false;
         }
         out << "(";
@@ -1109,8 +1112,8 @@
     std::ostream& out,
     const ast::CallExpression* expr,
     const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
-    const auto& args = expr->args;
-    auto* offset_arg = builder_.Sem().GetVal(args[1]);
+    auto const buffer = program_->Symbols().NameFor(intrinsic->buffer);
+    auto* const offset = expr->args[0];
 
     // offset in bytes
     uint32_t scalar_offset_bytes = 0;
@@ -1126,7 +1129,7 @@
     // If true, use scalar_offset_index, otherwise use scalar_offset_index_expr
     bool scalar_offset_constant = false;
 
-    if (auto* val = offset_arg->ConstantValue()) {
+    if (auto* val = builder_.Sem().GetVal(offset)->ConstantValue()) {
         TINT_ASSERT(Writer, val->Type()->Is<type::U32>());
         scalar_offset_bytes = static_cast<uint32_t>(val->ValueAs<AInt>());
         scalar_offset_index = scalar_offset_bytes / 4;  // bytes -> scalar index
@@ -1148,7 +1151,7 @@
             {
                 auto pre = line();
                 pre << "const uint " << scalar_offset_bytes_expr << " = (";
-                if (!EmitExpression(pre, args[1])) {  // offset
+                if (!EmitExpression(pre, offset)) {
                     return false;
                 }
                 pre << ");";
@@ -1159,7 +1162,7 @@
             scalar_offset_index_unified_expr = UniqueIdentifier("scalar_offset");
             auto pre = line();
             pre << "const uint " << scalar_offset_index_unified_expr << " = (";
-            if (!EmitExpression(pre, args[1])) {  // offset
+            if (!EmitExpression(pre, offset)) {
                 return false;
             }
             pre << ") / 4;";
@@ -1179,9 +1182,7 @@
                 return result;
             };
             auto load_u32_to = [&](std::ostream& target) {
-                if (!EmitExpression(target, args[0])) {  // buffer
-                    return false;
-                }
+                target << buffer;
                 if (scalar_offset_constant) {
                     target << "[" << (scalar_offset_index / 4) << "]."
                            << swizzle[scalar_offset_index & 3];
@@ -1195,20 +1196,14 @@
             // Has a minimum alignment of 8 bytes, so is either .xy or .zw
             auto load_vec2_u32_to = [&](std::ostream& target) {
                 if (scalar_offset_constant) {
-                    if (!EmitExpression(target, args[0])) {  // buffer
-                        return false;
-                    }
-                    target << "[" << (scalar_offset_index / 4) << "]";
-                    target << ((scalar_offset_index & 2) == 0 ? ".xy" : ".zw");
+                    target << buffer << "[" << (scalar_offset_index / 4) << "]"
+                           << ((scalar_offset_index & 2) == 0 ? ".xy" : ".zw");
                 } else {
                     std::string ubo_load = UniqueIdentifier("ubo_load");
                     {
                         auto pre = line();
-                        pre << "uint4 " << ubo_load << " = ";
-                        if (!EmitExpression(pre, args[0])) {  // buffer
-                            return false;
-                        }
-                        pre << "[" << scalar_offset_index_unified_expr << " / 4];";
+                        pre << "uint4 " << ubo_load << " = " << buffer << "["
+                            << scalar_offset_index_unified_expr << " / 4];";
                     }
                     target << "((" << scalar_offset_index_unified_expr << " & 2) ? " << ubo_load
                            << ".zw : " << ubo_load << ".xy)";
@@ -1218,9 +1213,7 @@
             auto load_vec2_u32 = [&] { return load_vec2_u32_to(out); };
             // vec4 has a minimum alignment of 16 bytes, easiest case
             auto load_vec4_u32 = [&] {
-                if (!EmitExpression(out, args[0])) {  // buffer
-                    return false;
-                }
+                out << buffer;
                 if (scalar_offset_constant) {
                     out << "[" << (scalar_offset_index / 4) << "]";
                 } else {
@@ -1239,10 +1232,7 @@
             auto load_scalar_f16 = [&] {
                 // offset bytes = 4k,   ((buffer[index].x) & 0xFFFF)
                 // offset bytes = 4k+2, ((buffer[index].x >> 16) & 0xFFFF)
-                out << "float16_t(f16tof32(((";
-                if (!EmitExpression(out, args[0])) {  // buffer
-                    return false;
-                }
+                out << "float16_t(f16tof32(((" << buffer;
                 if (scalar_offset_constant) {
                     out << "[" << (scalar_offset_index / 4) << "]."
                         << swizzle[scalar_offset_index & 3];
@@ -1410,7 +1400,9 @@
     std::ostream& out,
     const ast::CallExpression* expr,
     const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
-    const auto& args = expr->args;
+    auto const buffer = program_->Symbols().NameFor(intrinsic->buffer);
+    auto* const offset = expr->args[0];
+    auto* const value = expr->args[1];
 
     using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
     using DataType = transform::DecomposeMemoryAccess::Intrinsic::DataType;
@@ -1420,15 +1412,12 @@
                 if (cast) {
                     out << cast << "(";
                 }
-                if (!EmitExpression(out, args[0])) {  // buffer
-                    return false;
-                }
-                out << ".Load";
+                out << buffer << ".Load";
                 if (n > 1) {
                     out << n;
                 }
                 ScopedParen sp(out);
-                if (!EmitExpression(out, args[1])) {  // offset
+                if (!EmitExpression(out, offset)) {
                     return false;
                 }
                 if (cast) {
@@ -1440,12 +1429,9 @@
             // Used by loading f16 types, e.g. for f16 type, set type parameter to "float16_t"
             // to emit `buffer.Load<float16_t>(offset)`.
             auto templated_load = [&](const char* type) {
-                if (!EmitExpression(out, args[0])) {  // buffer
-                    return false;
-                }
-                out << ".Load<" << type << ">";  // templated load
+                out << buffer << ".Load<" << type << ">";  // templated load
                 ScopedParen sp(out);
-                if (!EmitExpression(out, args[1])) {  // offset
+                if (!EmitExpression(out, offset)) {
                     return false;
                 }
                 return true;
@@ -1492,20 +1478,17 @@
 
         case Op::kStore: {
             auto store = [&](int n) {
-                if (!EmitExpression(out, args[0])) {  // buffer
-                    return false;
-                }
-                out << ".Store";
+                out << buffer << ".Store";
                 if (n > 1) {
                     out << n;
                 }
                 ScopedParen sp1(out);
-                if (!EmitExpression(out, args[1])) {  // offset
+                if (!EmitExpression(out, offset)) {
                     return false;
                 }
                 out << ", asuint";
                 ScopedParen sp2(out);
-                if (!EmitExpression(out, args[2])) {  // value
+                if (!EmitExpression(out, value)) {
                     return false;
                 }
                 return true;
@@ -1514,16 +1497,13 @@
             // Used by storing f16 types, e.g. for f16 type, set type parameter to "float16_t"
             // to emit `buffer.Store<float16_t>(offset)`.
             auto templated_store = [&](const char* type) {
-                if (!EmitExpression(out, args[0])) {  // buffer
-                    return false;
-                }
-                out << ".Store<" << type << ">";  // templated store
+                out << buffer << ".Store<" << type << ">";  // templated store
                 ScopedParen sp1(out);
-                if (!EmitExpression(out, args[1])) {  // offset
+                if (!EmitExpression(out, offset)) {
                     return false;
                 }
                 out << ", ";
-                if (!EmitExpression(out, args[2])) {  // value
+                if (!EmitExpression(out, value)) {
                     return false;
                 }
                 return true;
@@ -1568,7 +1548,7 @@
             return false;
         }
         default:
-            // Break out to error case below/
+            // Break out to error case below
             // Note that atomic intrinsics are generated as functions.
             break;
     }
@@ -1585,20 +1565,21 @@
 
     const sem::Function* sem_func = builder_.Sem().Get(func);
     auto* result_ty = sem_func->ReturnType();
-    const auto& params = sem_func->Parameters();
     const auto name = builder_.Symbols().NameFor(func->name->symbol);
     auto& buf = *current_buffer_;
 
+    auto const buffer = program_->Symbols().NameFor(intrinsic->buffer);
+
     auto rmw = [&](const char* hlsl) -> bool {
         {
             auto fn = line(&buf);
-            if (!EmitTypeAndName(fn, result_ty, type::AddressSpace::kNone, type::Access::kUndefined,
-                                 name)) {
+            if (!EmitTypeAndName(fn, result_ty, builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, name)) {
                 return false;
             }
-            fn << "(RWByteAddressBuffer buffer, uint offset, ";
-            if (!EmitTypeAndName(fn, result_ty, type::AddressSpace::kNone, type::Access::kUndefined,
-                                 "value")) {
+            fn << "(uint offset, ";
+            if (!EmitTypeAndName(fn, result_ty, builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, "value")) {
                 return false;
             }
             fn << ") {";
@@ -1613,15 +1594,15 @@
 
         {
             auto l = line(&buf);
-            if (!EmitTypeAndName(l, result_ty, type::AddressSpace::kNone, type::Access::kUndefined,
-                                 "original_value")) {
+            if (!EmitTypeAndName(l, result_ty, builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, "original_value")) {
                 return false;
             }
             l << " = 0;";
         }
         {
             auto l = line(&buf);
-            l << "buffer." << hlsl << "(offset, ";
+            l << buffer << "." << hlsl << "(offset, ";
             if (intrinsic->op == Op::kAtomicSub) {
                 l << "-";
             }
@@ -1662,11 +1643,11 @@
             // InterlockedOr using 0 as the OR value
             {
                 auto fn = line(&buf);
-                if (!EmitTypeAndName(fn, result_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, name)) {
+                if (!EmitTypeAndName(fn, result_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, name)) {
                     return false;
                 }
-                fn << "(RWByteAddressBuffer buffer, uint offset) {";
+                fn << "(uint offset) {";
             }
 
             buf.IncrementIndent();
@@ -1678,26 +1659,26 @@
 
             {
                 auto l = line(&buf);
-                if (!EmitTypeAndName(l, result_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, "value")) {
+                if (!EmitTypeAndName(l, result_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, "value")) {
                     return false;
                 }
                 l << " = 0;";
             }
 
-            line(&buf) << "buffer.InterlockedOr(offset, 0, value);";
+            line(&buf) << buffer << ".InterlockedOr(offset, 0, value);";
             line(&buf) << "return value;";
             return true;
         }
         case Op::kAtomicStore: {
+            auto* const value_ty = sem_func->Parameters()[1]->Type()->UnwrapRef();
             // HLSL does not have an InterlockedStore, so we emulate it with
             // InterlockedExchange and discard the returned value
-            auto* value_ty = params[2]->Type()->UnwrapRef();
             {
                 auto fn = line(&buf);
-                fn << "void " << name << "(RWByteAddressBuffer buffer, uint offset, ";
-                if (!EmitTypeAndName(fn, value_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, "value")) {
+                fn << "void " << name << "(uint offset, ";
+                if (!EmitTypeAndName(fn, value_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, "value")) {
                     return false;
                 }
                 fn << ") {";
@@ -1712,33 +1693,33 @@
 
             {
                 auto l = line(&buf);
-                if (!EmitTypeAndName(l, value_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, "ignored")) {
+                if (!EmitTypeAndName(l, value_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, "ignored")) {
                     return false;
                 }
                 l << ";";
             }
-            line(&buf) << "buffer.InterlockedExchange(offset, value, ignored);";
+            line(&buf) << buffer << ".InterlockedExchange(offset, value, ignored);";
             return true;
         }
         case Op::kAtomicCompareExchangeWeak: {
+            auto* const value_ty = sem_func->Parameters()[1]->Type()->UnwrapRef();
             // NOTE: We don't need to emit the return type struct here as DecomposeMemoryAccess
             // already added it to the AST, and it should have already been emitted by now.
-            auto* value_ty = params[2]->Type()->UnwrapRef();
             {
                 auto fn = line(&buf);
-                if (!EmitTypeAndName(fn, result_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, name)) {
+                if (!EmitTypeAndName(fn, result_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, name)) {
                     return false;
                 }
-                fn << "(RWByteAddressBuffer buffer, uint offset, ";
-                if (!EmitTypeAndName(fn, value_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, "compare")) {
+                fn << "(uint offset, ";
+                if (!EmitTypeAndName(fn, value_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, "compare")) {
                     return false;
                 }
                 fn << ", ";
-                if (!EmitTypeAndName(fn, value_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, "value")) {
+                if (!EmitTypeAndName(fn, value_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, "value")) {
                     return false;
                 }
                 fn << ") {";
@@ -1753,8 +1734,8 @@
 
             {  // T result = {0};
                 auto l = line(&buf);
-                if (!EmitTypeAndName(l, result_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, "result")) {
+                if (!EmitTypeAndName(l, result_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, "result")) {
                     return false;
                 }
                 l << "=";
@@ -1764,8 +1745,8 @@
                 l << ";";
             }
 
-            line(&buf) << "buffer.InterlockedCompareExchange(offset, compare, value, "
-                          "result.old_value);";
+            line(&buf) << buffer
+                       << ".InterlockedCompareExchange(offset, compare, value, result.old_value);";
             line(&buf) << "result.exchanged = result.old_value == compare;";
             line(&buf) << "return result;";
 
@@ -1788,8 +1769,8 @@
 
     if (!builtin->ReturnType()->Is<type::Void>()) {
         auto pre = line();
-        if (!EmitTypeAndName(pre, builtin->ReturnType(), type::AddressSpace::kNone,
-                             type::Access::kUndefined, result)) {
+        if (!EmitTypeAndName(pre, builtin->ReturnType(), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kUndefined, result)) {
             return false;
         }
         pre << " = ";
@@ -1852,8 +1833,8 @@
             {  // T result = 0;
                 auto pre = line();
                 auto* value_ty = builtin->Parameters()[1]->Type()->UnwrapRef();
-                if (!EmitTypeAndName(pre, value_ty, type::AddressSpace::kNone,
-                                     type::Access::kUndefined, result)) {
+                if (!EmitTypeAndName(pre, value_ty, builtin::AddressSpace::kUndefined,
+                                     builtin::Access::kUndefined, result)) {
                     return false;
                 }
                 pre << " = ";
@@ -1891,7 +1872,7 @@
             {  // T compare_value = <compare_value>;
                 auto pre = line();
                 if (!EmitTypeAndName(pre, TypeOf(compare_value)->UnwrapRef(),
-                                     type::AddressSpace::kNone, type::Access::kUndefined,
+                                     builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
                                      compare)) {
                     return false;
                 }
@@ -2001,8 +1982,8 @@
 
             {
                 auto l = line(b);
-                if (!EmitType(l, builtin->ReturnType(), type::AddressSpace::kNone,
-                              type::Access::kUndefined, "")) {
+                if (!EmitType(l, builtin->ReturnType(), builtin::AddressSpace::kUndefined,
+                              builtin::Access::kUndefined, "")) {
                     return false;
                 }
                 l << " result;";
@@ -2043,8 +2024,8 @@
             line(b) << member_type << " fract = frexp(" << in << ", exp);";
             {
                 auto l = line(b);
-                if (!EmitType(l, builtin->ReturnType(), type::AddressSpace::kNone,
-                              type::Access::kUndefined, "")) {
+                if (!EmitType(l, builtin->ReturnType(), builtin::AddressSpace::kUndefined,
+                              builtin::Access::kUndefined, "")) {
                     return false;
                 }
                 l << " result = {fract, int" << width << "(exp)};";
@@ -2081,7 +2062,8 @@
 // type after the call to `sign`.
 bool GeneratorImpl::EmitSignCall(std::ostream& out, const sem::Call* call, const sem::Builtin*) {
     auto* arg = call->Arguments()[0];
-    if (!EmitType(out, arg->Type(), type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+    if (!EmitType(out, arg->Type(), builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                  "")) {
         return false;
     }
     out << "(sign(";
@@ -2861,7 +2843,7 @@
     // Emit storage atomic helpers
     if (auto* intrinsic =
             ast::GetAttribute<transform::DecomposeMemoryAccess::Intrinsic>(func->attributes)) {
-        if (intrinsic->address_space == type::AddressSpace::kStorage && intrinsic->IsAtomic()) {
+        if (intrinsic->address_space == builtin::AddressSpace::kStorage && intrinsic->IsAtomic()) {
             if (!EmitStorageAtomicIntrinsic(func, intrinsic)) {
                 return false;
             }
@@ -2883,15 +2865,15 @@
             auto typedef_name = UniqueIdentifier(name + "_ret");
             auto pre = line();
             pre << "typedef ";
-            if (!EmitTypeAndName(pre, sem->ReturnType(), type::AddressSpace::kNone,
-                                 type::Access::kReadWrite, typedef_name)) {
+            if (!EmitTypeAndName(pre, sem->ReturnType(), builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kReadWrite, typedef_name)) {
                 return false;
             }
             pre << ";";
             out << typedef_name;
         } else {
-            if (!EmitType(out, sem->ReturnType(), type::AddressSpace::kNone,
-                          type::Access::kReadWrite, "")) {
+            if (!EmitType(out, sem->ReturnType(), builtin::AddressSpace::kUndefined,
+                          builtin::Access::kReadWrite, "")) {
                 return false;
             }
         }
@@ -2907,14 +2889,14 @@
             first = false;
 
             auto const* type = v->Type();
-            auto address_space = type::AddressSpace::kNone;
-            auto access = type::Access::kUndefined;
+            auto address_space = builtin::AddressSpace::kUndefined;
+            auto access = builtin::Access::kUndefined;
 
             if (auto* ptr = type->As<type::Pointer>()) {
                 type = ptr->StoreType();
                 switch (ptr->AddressSpace()) {
-                    case type::AddressSpace::kStorage:
-                    case type::AddressSpace::kUniform:
+                    case builtin::AddressSpace::kStorage:
+                    case builtin::AddressSpace::kUniform:
                         // Not allowed by WGSL, but is used by certain transforms (e.g. DMA) to pass
                         // storage buffers and uniform buffers down into transform-generated
                         // functions. In this situation we want to generate the parameter without an
@@ -2928,7 +2910,7 @@
                 }
             }
 
-            // Note: WGSL only allows for AddressSpace::kNone on parameters, however
+            // Note: WGSL only allows for AddressSpace::kUndefined on parameters, however
             // the sanitizer transforms generates load / store functions for storage
             // or uniform buffers. These functions have a buffer parameter with
             // AddressSpace::kStorage or AddressSpace::kUniform. This is required to
@@ -2981,8 +2963,8 @@
     auto name = builder_.Symbols().NameFor(builder_.Symbols().New("unused"));
     {
         auto out = line();
-        if (!EmitTypeAndName(out, sem->ReturnType(), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, name)) {
+        if (!EmitTypeAndName(out, sem->ReturnType(), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, name)) {
             return false;
         }
         out << ";";
@@ -2998,17 +2980,17 @@
         [&](const ast::Var* var) {
             auto* sem = builder_.Sem().Get(global);
             switch (sem->AddressSpace()) {
-                case type::AddressSpace::kUniform:
+                case builtin::AddressSpace::kUniform:
                     return EmitUniformVariable(var, sem);
-                case type::AddressSpace::kStorage:
+                case builtin::AddressSpace::kStorage:
                     return EmitStorageVariable(var, sem);
-                case type::AddressSpace::kHandle:
+                case builtin::AddressSpace::kHandle:
                     return EmitHandleVariable(var, sem);
-                case type::AddressSpace::kPrivate:
+                case builtin::AddressSpace::kPrivate:
                     return EmitPrivateVariable(sem);
-                case type::AddressSpace::kWorkgroup:
+                case builtin::AddressSpace::kWorkgroup:
                     return EmitWorkgroupVariable(sem);
-                case type::AddressSpace::kPushConstant:
+                case builtin::AddressSpace::kPushConstant:
                     diagnostics_.add_error(
                         diag::System::Writer,
                         "unhandled address space " + utils::ToString(sem->AddressSpace()));
@@ -3047,7 +3029,7 @@
     {
         ScopedIndent si(this);
         auto out = line();
-        if (!EmitTypeAndName(out, type, type::AddressSpace::kUniform, sem->Access(), name)) {
+        if (!EmitTypeAndName(out, type, builtin::AddressSpace::kUniform, sem->Access(), name)) {
             return false;
         }
         out << ";";
@@ -3061,13 +3043,13 @@
 bool GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable* sem) {
     auto* type = sem->Type()->UnwrapRef();
     auto out = line();
-    if (!EmitTypeAndName(out, type, type::AddressSpace::kStorage, sem->Access(),
+    if (!EmitTypeAndName(out, type, builtin::AddressSpace::kStorage, sem->Access(),
                          builder_.Symbols().NameFor(var->name->symbol))) {
         return false;
     }
 
     auto* global_sem = sem->As<sem::GlobalVariable>();
-    out << RegisterAndSpace(sem->Access() == type::Access::kRead ? 't' : 'u',
+    out << RegisterAndSpace(sem->Access() == builtin::Access::kRead ? 't' : 'u',
                             global_sem->BindingPoint())
         << ";";
 
@@ -3184,31 +3166,32 @@
     return "";
 }
 
-std::string GeneratorImpl::interpolation_to_modifiers(ast::InterpolationType type,
-                                                      ast::InterpolationSampling sampling) const {
+std::string GeneratorImpl::interpolation_to_modifiers(
+    builtin::InterpolationType type,
+    builtin::InterpolationSampling sampling) const {
     std::string modifiers;
     switch (type) {
-        case ast::InterpolationType::kPerspective:
+        case builtin::InterpolationType::kPerspective:
             modifiers += "linear ";
             break;
-        case ast::InterpolationType::kLinear:
+        case builtin::InterpolationType::kLinear:
             modifiers += "noperspective ";
             break;
-        case ast::InterpolationType::kFlat:
+        case builtin::InterpolationType::kFlat:
             modifiers += "nointerpolation ";
             break;
-        case ast::InterpolationType::kUndefined:
+        case builtin::InterpolationType::kUndefined:
             break;
     }
     switch (sampling) {
-        case ast::InterpolationSampling::kCentroid:
+        case builtin::InterpolationSampling::kCentroid:
             modifiers += "centroid ";
             break;
-        case ast::InterpolationSampling::kSample:
+        case builtin::InterpolationSampling::kSample:
             modifiers += "sample ";
             break;
-        case ast::InterpolationSampling::kCenter:
-        case ast::InterpolationSampling::kUndefined:
+        case builtin::InterpolationSampling::kCenter:
+        case builtin::InterpolationSampling::kUndefined:
             break;
     }
     return modifiers;
@@ -3239,8 +3222,8 @@
             out << ")]" << std::endl;
         }
 
-        if (!EmitTypeAndName(out, func_sem->ReturnType(), type::AddressSpace::kUndefined,
-                             type::Access::kUndefined,
+        if (!EmitTypeAndName(out, func_sem->ReturnType(), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kUndefined,
                              builder_.Symbols().NameFor(func->name->symbol))) {
             return false;
         }
@@ -3335,7 +3318,8 @@
                 return true;
             }
 
-            if (!EmitType(out, v, type::AddressSpace::kNone, type::Access::kUndefined, "")) {
+            if (!EmitType(out, v, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
+                          "")) {
                 return false;
             }
 
@@ -3352,7 +3336,8 @@
             return true;
         },
         [&](const type::Matrix* m) {
-            if (!EmitType(out, m, type::AddressSpace::kNone, type::Access::kUndefined, "")) {
+            if (!EmitType(out, m, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
+                          "")) {
                 return false;
             }
 
@@ -3371,7 +3356,8 @@
         [&](const type::Array* a) {
             if (constant->AllZero()) {
                 out << "(";
-                if (!EmitType(out, a, type::AddressSpace::kNone, type::Access::kUndefined, "")) {
+                if (!EmitType(out, a, builtin::AddressSpace::kUndefined,
+                              builtin::Access::kUndefined, "")) {
                     return false;
                 }
                 out << ")0";
@@ -3511,7 +3497,8 @@
             return true;
         },
         [&](const type::Vector* vec) {
-            if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+            if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                          "")) {
                 return false;
             }
             ScopedParen sp(out);
@@ -3526,7 +3513,8 @@
             return true;
         },
         [&](const type::Matrix* mat) {
-            if (!EmitType(out, type, type::AddressSpace::kNone, type::Access::kReadWrite, "")) {
+            if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
+                          "")) {
                 return false;
             }
             ScopedParen sp(out);
@@ -3543,12 +3531,14 @@
         [&](const sem::Struct*) {
             out << "(";
             TINT_DEFER(out << ")" << value);
-            return EmitType(out, type, type::AddressSpace::kNone, type::Access::kUndefined, "");
+            return EmitType(out, type, builtin::AddressSpace::kUndefined,
+                            builtin::Access::kUndefined, "");
         },
         [&](const type::Array*) {
             out << "(";
             TINT_DEFER(out << ")" << value);
-            return EmitType(out, type, type::AddressSpace::kNone, type::Access::kUndefined, "");
+            return EmitType(out, type, builtin::AddressSpace::kUndefined,
+                            builtin::Access::kUndefined, "");
         },
         [&](Default) {
             diagnostics_.add_error(
@@ -3922,21 +3912,21 @@
 
 bool GeneratorImpl::EmitType(std::ostream& out,
                              const type::Type* type,
-                             type::AddressSpace address_space,
-                             type::Access access,
+                             builtin::AddressSpace address_space,
+                             builtin::Access access,
                              const std::string& name,
                              bool* name_printed /* = nullptr */) {
     if (name_printed) {
         *name_printed = false;
     }
     switch (address_space) {
-        case type::AddressSpace::kStorage:
-            if (access != type::Access::kRead) {
+        case builtin::AddressSpace::kStorage:
+            if (access != builtin::Access::kRead) {
                 out << "RW";
             }
             out << "ByteAddressBuffer";
             return true;
-        case type::AddressSpace::kUniform: {
+        case builtin::AddressSpace::kUniform: {
             auto array_length = (type->Size() + 15) / 16;
             out << "uint4 " << name << "[" << array_length << "]";
             if (name_printed) {
@@ -4053,7 +4043,7 @@
             auto* depth_ms = tex->As<type::DepthMultisampledTexture>();
             auto* sampled = tex->As<type::SampledTexture>();
 
-            if (storage && storage->access() != type::Access::kRead) {
+            if (storage && storage->access() != builtin::Access::kRead) {
                 out << "RW";
             }
             out << "Texture";
@@ -4149,8 +4139,8 @@
 
 bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
                                     const type::Type* type,
-                                    type::AddressSpace address_space,
-                                    type::Access access,
+                                    builtin::AddressSpace address_space,
+                                    builtin::Access access,
                                     const std::string& name) {
     bool name_printed = false;
     if (!EmitType(out, type, address_space, access, name, &name_printed)) {
@@ -4199,16 +4189,30 @@
                         } else {
                             TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute";
                         }
-                    } else if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
-                        auto name = builtin_to_attribute(builtin->builtin);
+                    } else if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
+                        auto builtin = program_->Sem().Get(builtin_attr)->Value();
+                        auto name = builtin_to_attribute(builtin);
                         if (name.empty()) {
                             diagnostics_.add_error(diag::System::Writer, "unsupported builtin");
                             return false;
                         }
                         post += " : " + name;
                     } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
-                        auto mod =
-                            interpolation_to_modifiers(interpolate->type, interpolate->sampling);
+                        auto& sem = program_->Sem();
+                        auto i_type =
+                            sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(
+                                   interpolate->type)
+                                ->Value();
+
+                        auto i_smpl = builtin::InterpolationSampling::kUndefined;
+                        if (interpolate->sampling) {
+                            i_smpl =
+                                sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
+                                       interpolate->sampling)
+                                    ->Value();
+                        }
+
+                        auto mod = interpolation_to_modifiers(i_type, i_smpl);
                         if (mod.empty()) {
                             diagnostics_.add_error(diag::System::Writer,
                                                    "unsupported interpolation");
@@ -4232,8 +4236,8 @@
             }
 
             out << pre;
-            if (!EmitTypeAndName(out, ty, type::AddressSpace::kNone, type::Access::kReadWrite,
-                                 mem_name)) {
+            if (!EmitTypeAndName(out, ty, builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kReadWrite, mem_name)) {
                 return false;
             }
             out << post << ";";
@@ -4302,7 +4306,7 @@
 
     auto out = line();
     out << "const ";
-    if (!EmitTypeAndName(out, type, type::AddressSpace::kNone, type::Access::kUndefined,
+    if (!EmitTypeAndName(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
                          builder_.Symbols().NameFor(let->name->symbol))) {
         return false;
     }
@@ -4329,8 +4333,8 @@
         std::vector<std::string> parameter_names;
         {
             auto decl = line(&b);
-            if (!EmitTypeAndName(decl, builtin->ReturnType(), type::AddressSpace::kNone,
-                                 type::Access::kUndefined, fn_name)) {
+            if (!EmitTypeAndName(decl, builtin->ReturnType(), builtin::AddressSpace::kUndefined,
+                                 builtin::Access::kUndefined, fn_name)) {
                 return "";
             }
             {
@@ -4345,8 +4349,8 @@
                         decl << "inout ";
                         ty = ptr->StoreType();
                     }
-                    if (!EmitTypeAndName(decl, ty, type::AddressSpace::kNone,
-                                         type::Access::kUndefined, param_name)) {
+                    if (!EmitTypeAndName(decl, ty, builtin::AddressSpace::kUndefined,
+                                         builtin::Access::kUndefined, param_name)) {
                         return "";
                     }
                     parameter_names.emplace_back(std::move(param_name));
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index b5f53bf..6db120c 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -31,6 +31,7 @@
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/switch_statement.h"
 #include "src/tint/ast/unary_op_expression.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/scope_stack.h"
 #include "src/tint/sem/binding_point.h"
@@ -42,10 +43,10 @@
 
 // Forward declarations
 namespace tint::sem {
-class Call;
 class Builtin;
-class TypeInitializer;
-class TypeConversion;
+class Call;
+class ValueConstructor;
+class ValueConversion;
 }  // namespace tint::sem
 
 namespace tint::writer::hlsl {
@@ -139,22 +140,22 @@
     /// @param builtin the builtin being called
     /// @returns true if the expression is emitted
     bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
-    /// Handles generating a type conversion expression
+    /// Handles generating a value conversion expression
     /// @param out the output of the expression stream
     /// @param call the call expression
-    /// @param conv the type conversion
+    /// @param conv the value conversion
     /// @returns true if the expression is emitted
-    bool EmitTypeConversion(std::ostream& out,
-                            const sem::Call* call,
-                            const sem::TypeConversion* conv);
-    /// Handles generating a type initializer expression
-    /// @param out the output of the expression stream
-    /// @param call the call expression
-    /// @param ctor the type initializer
-    /// @returns true if the expression is emitted
-    bool EmitTypeInitializer(std::ostream& out,
+    bool EmitValueConversion(std::ostream& out,
                              const sem::Call* call,
-                             const sem::TypeInitializer* ctor);
+                             const sem::ValueConversion* conv);
+    /// Handles generating a value constructor expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param ctor the value constructor
+    /// @returns true if the expression is emitted
+    bool EmitValueConstructor(std::ostream& out,
+                              const sem::Call* call,
+                              const sem::ValueConstructor* ctor);
     /// Handles generating a call expression to a
     /// transform::DecomposeMemoryAccess::Intrinsic for a uniform buffer
     /// @param out the output of the expression stream
@@ -413,8 +414,8 @@
     /// @returns true if the type is emitted
     bool EmitType(std::ostream& out,
                   const type::Type* type,
-                  type::AddressSpace address_space,
-                  type::Access access,
+                  builtin::AddressSpace address_space,
+                  builtin::Access access,
                   const std::string& name,
                   bool* name_printed = nullptr);
     /// Handles generating type and name
@@ -426,8 +427,8 @@
     /// @returns true if the type is emitted
     bool EmitTypeAndName(std::ostream& out,
                          const type::Type* type,
-                         type::AddressSpace address_space,
-                         type::Access access,
+                         builtin::AddressSpace address_space,
+                         builtin::Access access,
                          const std::string& name);
     /// Handles generating a structure declaration. If the structure has already been emitted, then
     /// this function will simply return `true` without emitting anything.
@@ -501,8 +502,8 @@
     /// @param type the interpolation type
     /// @param sampling the interpolation sampling
     /// @returns the string name of the attribute or blank on error
-    std::string interpolation_to_modifiers(ast::InterpolationType type,
-                                           ast::InterpolationSampling sampling) const;
+    std::string interpolation_to_modifiers(builtin::InterpolationType type,
+                                           builtin::InterpolationSampling sampling) const;
 
   private:
     enum class VarType { kIn, kOut };
diff --git a/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc b/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
index 71bf057..73eea96 100644
--- a/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
@@ -22,7 +22,7 @@
 using HlslGeneratorImplTest_Expression = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Expression, IndexAccessor) {
-    GlobalVar("ary", ty.array<i32, 10>(), type::AddressSpace::kPrivate);
+    GlobalVar("ary", ty.array<i32, 10>(), builtin::AddressSpace::kPrivate);
     auto* expr = IndexAccessor("ary", 5_i);
     WrapInFunction(expr);
 
diff --git a/src/tint/writer/hlsl/generator_impl_binary_test.cc b/src/tint/writer/hlsl/generator_impl_binary_test.cc
index 325ca67..c99ae54 100644
--- a/src/tint/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_binary_test.cc
@@ -50,8 +50,8 @@
         return;
     }
 
-    GlobalVar("left", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("right", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("left", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* left = Expr("left");
     auto* right = Expr("right");
@@ -82,8 +82,8 @@
 
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("left", ty.f16(), type::AddressSpace::kPrivate);
-    GlobalVar("right", ty.f16(), type::AddressSpace::kPrivate);
+    GlobalVar("left", ty.f16(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", ty.f16(), builtin::AddressSpace::kPrivate);
 
     auto* left = Expr("left");
     auto* right = Expr("right");
@@ -105,8 +105,8 @@
         return;
     }
 
-    GlobalVar("left", ty.u32(), type::AddressSpace::kPrivate);
-    GlobalVar("right", ty.u32(), type::AddressSpace::kPrivate);
+    GlobalVar("left", ty.u32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", ty.u32(), builtin::AddressSpace::kPrivate);
 
     auto* left = Expr("left");
     auto* right = Expr("right");
@@ -133,8 +133,8 @@
         return;
     }
 
-    GlobalVar("left", ty.i32(), type::AddressSpace::kPrivate);
-    GlobalVar("right", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("left", ty.i32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* left = Expr("left");
     auto* right = Expr("right");
@@ -237,7 +237,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f32) {
-    GlobalVar("mat", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
     auto* rhs = Expr(1_f);
 
@@ -254,7 +254,7 @@
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
     auto* rhs = Expr(1_h);
 
@@ -269,7 +269,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f32) {
-    GlobalVar("mat", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr(1_f);
     auto* rhs = Expr("mat");
 
@@ -286,7 +286,7 @@
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr(1_h);
     auto* rhs = Expr("mat");
 
@@ -301,7 +301,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector_f32) {
-    GlobalVar("mat", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
     auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
 
@@ -318,7 +318,7 @@
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
     auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
 
@@ -333,7 +333,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f32) {
-    GlobalVar("mat", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
     auto* rhs = Expr("mat");
 
@@ -350,7 +350,7 @@
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
     auto* rhs = Expr("mat");
 
@@ -365,8 +365,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f32) {
-    GlobalVar("lhs", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("rhs", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("lhs", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -381,8 +381,8 @@
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("lhs", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
-    GlobalVar("rhs", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    GlobalVar("lhs", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
     WrapInFunction(expr);
@@ -395,8 +395,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Logical_And) {
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -415,10 +415,10 @@
 
 TEST_F(HlslGeneratorImplTest_Binary, Logical_Multi) {
     // (a && b) || (c || d)
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("d", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(
         ast::BinaryOp::kLogicalOr,
@@ -447,8 +447,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Logical_Or) {
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
     WrapInFunction(expr);
@@ -474,9 +474,9 @@
     //   return 3i;
     // }
 
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr =
         If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
@@ -511,9 +511,9 @@
 TEST_F(HlslGeneratorImplTest_Binary, Return_WithLogical) {
     // return (a && b) || c;
 
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Return(create<ast::BinaryExpression>(
         ast::BinaryOp::kLogicalOr,
@@ -539,10 +539,10 @@
 TEST_F(HlslGeneratorImplTest_Binary, Assign_WithLogical) {
     // a = (b || c) && d;
 
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("d", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* expr =
         Assign(Expr("a"),
@@ -570,12 +570,12 @@
 TEST_F(HlslGeneratorImplTest_Binary, Decl_WithLogical) {
     // var a : bool = (b && c) || d;
 
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("d", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* var =
-        Var("a", ty.bool_(), type::AddressSpace::kNone,
+        Var("a", ty.bool_(), builtin::AddressSpace::kUndefined,
             create<ast::BinaryExpression>(
                 ast::BinaryOp::kLogicalOr,
                 create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("b"), Expr("c")),
@@ -609,10 +609,10 @@
              Param(Sym(), ty.bool_()),
          },
          ty.void_(), utils::Empty, utils::Empty);
-    GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("d", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     utils::Vector params{
         create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index 9811b79..7cd3de3 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -197,25 +197,25 @@
     if (param.type == CallParamType::kF16) {
         Enable(builtin::Extension::kF16);
 
-        GlobalVar("h2", ty.vec2<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("h3", ty.vec3<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("hm2x2", ty.mat2x2<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("hm3x2", ty.mat3x2<f16>(), type::AddressSpace::kPrivate);
+        GlobalVar("h2", ty.vec2<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("h3", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("hm2x2", ty.mat2x2<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("hm3x2", ty.mat3x2<f16>(), builtin::AddressSpace::kPrivate);
     }
 
-    GlobalVar("f2", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("f3", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("u2", ty.vec2<u32>(), type::AddressSpace::kPrivate);
-    GlobalVar("i2", ty.vec2<i32>(), type::AddressSpace::kPrivate);
-    GlobalVar("b2", ty.vec2<bool>(), type::AddressSpace::kPrivate);
-    GlobalVar("m2x2", ty.mat2x2<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("m3x2", ty.mat3x2<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("f2", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("f3", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("u2", ty.vec2<u32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("i2", ty.vec2<i32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b2", ty.vec2<bool>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("m2x2", ty.mat2x2<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("m3x2", ty.mat3x2<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* call = GenerateCall(param.builtin, param.type, this);
     ASSERT_NE(nullptr, call) << "Unhandled builtin";
     Func("func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(call),
+             Assign(Phony(), call),
          },
          utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
@@ -339,10 +339,10 @@
 TEST_F(HlslGeneratorImplTest_Builtin, Builtin_Call) {
     auto* call = Call("dot", "param1", "param2");
 
-    GlobalVar("param1", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
 
     GeneratorImpl& gen = Build();
 
@@ -353,10 +353,10 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Select_Scalar) {
-    GlobalVar("a", Expr(1_f), type::AddressSpace::kPrivate);
-    GlobalVar("b", Expr(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("a", Expr(1_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", Expr(2_f), builtin::AddressSpace::kPrivate);
     auto* call = Call("select", "a", "b", true);
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
@@ -366,10 +366,10 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Select_Vector) {
-    GlobalVar("a", vec2<i32>(1_i, 2_i), type::AddressSpace::kPrivate);
-    GlobalVar("b", vec2<i32>(3_i, 4_i), type::AddressSpace::kPrivate);
+    GlobalVar("a", vec2<i32>(1_i, 2_i), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", vec2<i32>(3_i, 4_i), builtin::AddressSpace::kPrivate);
     auto* call = Call("select", "a", "b", vec2<bool>(true, false));
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
@@ -1086,8 +1086,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack4x8Snorm) {
     auto* call = Call("pack4x8snorm", "p1");
-    GlobalVar("p1", ty.vec4<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1100,7 +1100,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_pack4x8snorm(p1);
+  uint r = tint_pack4x8snorm(p1);
   return;
 }
 )");
@@ -1108,8 +1108,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack4x8Unorm) {
     auto* call = Call("pack4x8unorm", "p1");
-    GlobalVar("p1", ty.vec4<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1122,7 +1122,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_pack4x8unorm(p1);
+  uint r = tint_pack4x8unorm(p1);
   return;
 }
 )");
@@ -1130,8 +1130,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Snorm) {
     auto* call = Call("pack2x16snorm", "p1");
-    GlobalVar("p1", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1144,7 +1144,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_pack2x16snorm(p1);
+  uint r = tint_pack2x16snorm(p1);
   return;
 }
 )");
@@ -1152,8 +1152,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Unorm) {
     auto* call = Call("pack2x16unorm", "p1");
-    GlobalVar("p1", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1166,7 +1166,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_pack2x16unorm(p1);
+  uint r = tint_pack2x16unorm(p1);
   return;
 }
 )");
@@ -1174,8 +1174,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Float) {
     auto* call = Call("pack2x16float", "p1");
-    GlobalVar("p1", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1188,7 +1188,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_pack2x16float(p1);
+  uint r = tint_pack2x16float(p1);
   return;
 }
 )");
@@ -1196,8 +1196,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack4x8Snorm) {
     auto* call = Call("unpack4x8snorm", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1211,7 +1211,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_unpack4x8snorm(p1);
+  float4 r = tint_unpack4x8snorm(p1);
   return;
 }
 )");
@@ -1219,8 +1219,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack4x8Unorm) {
     auto* call = Call("unpack4x8unorm", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1234,7 +1234,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_unpack4x8unorm(p1);
+  float4 r = tint_unpack4x8unorm(p1);
   return;
 }
 )");
@@ -1242,8 +1242,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Snorm) {
     auto* call = Call("unpack2x16snorm", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1257,7 +1257,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_unpack2x16snorm(p1);
+  float2 r = tint_unpack2x16snorm(p1);
   return;
 }
 )");
@@ -1265,8 +1265,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Unorm) {
     auto* call = Call("unpack2x16unorm", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1280,7 +1280,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_unpack2x16unorm(p1);
+  float2 r = tint_unpack2x16unorm(p1);
   return;
 }
 )");
@@ -1288,8 +1288,8 @@
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Float) {
     auto* call = Call("unpack2x16float", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
@@ -1302,7 +1302,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  tint_unpack2x16float(p1);
+  float2 r = tint_unpack2x16float(p1);
   return;
 }
 )");
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
index 4b15133..4d7165b 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
@@ -373,7 +373,8 @@
     param.BuildSamplerVariable(this);
 
     auto* call = Call(param.function, param.args(this));
-    auto* stmt = CallStmt(call);
+    auto* stmt = param.returns_value ? static_cast<const ast::Statement*>(Decl(Var("v", call)))
+                                     : static_cast<const ast::Statement*>(CallStmt(call));
 
     Func("main", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
diff --git a/src/tint/writer/hlsl/generator_impl_call_test.cc b/src/tint/writer/hlsl/generator_impl_call_test.cc
index 46b1406..9947a08 100644
--- a/src/tint/writer/hlsl/generator_impl_call_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_call_test.cc
@@ -42,8 +42,8 @@
              Param(Sym(), ty.f32()),
          },
          ty.f32(), utils::Vector{Return(1.23_f)});
-    GlobalVar("param1", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("my_func", "param1", "param2");
     WrapInFunction(call);
@@ -62,8 +62,8 @@
              Param(Sym(), ty.f32()),
          },
          ty.void_(), utils::Empty, utils::Empty);
-    GlobalVar("param1", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = CallStmt(Call("my_func", "param1", "param2"));
     WrapInFunction(call);
diff --git a/src/tint/writer/hlsl/generator_impl_initializer_test.cc b/src/tint/writer/hlsl/generator_impl_constructor_test.cc
similarity index 80%
rename from src/tint/writer/hlsl/generator_impl_initializer_test.cc
rename to src/tint/writer/hlsl/generator_impl_constructor_test.cc
index ebc206a..6cd264e 100644
--- a/src/tint/writer/hlsl/generator_impl_initializer_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_constructor_test.cc
@@ -22,9 +22,9 @@
 
 using ::testing::HasSubstr;
 
-using HlslGeneratorImplTest_Initializer = TestHelper;
+using HlslGeneratorImplTest_Constructor = TestHelper;
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Bool) {
+TEST_F(HlslGeneratorImplTest_Constructor, Bool) {
     WrapInFunction(Expr(false));
 
     GeneratorImpl& gen = Build();
@@ -33,7 +33,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Int) {
+TEST_F(HlslGeneratorImplTest_Constructor, Int) {
     WrapInFunction(Expr(-12345_i));
 
     GeneratorImpl& gen = Build();
@@ -42,7 +42,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_UInt) {
+TEST_F(HlslGeneratorImplTest_Constructor, UInt) {
     WrapInFunction(Expr(56779_u));
 
     GeneratorImpl& gen = Build();
@@ -51,7 +51,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Float) {
+TEST_F(HlslGeneratorImplTest_Constructor, Float) {
     // Use a number close to 1<<30 but whose decimal representation ends in 0.
     WrapInFunction(Expr(f32((1 << 30) - 4)));
 
@@ -61,7 +61,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_F16) {
+TEST_F(HlslGeneratorImplTest_Constructor, F16) {
     Enable(builtin::Extension::kF16);
 
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
@@ -73,7 +73,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float16_t(32752.0h)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Float) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Float) {
     WrapInFunction(Call<f32>(-1.2e-5_f));
 
     GeneratorImpl& gen = Build();
@@ -82,7 +82,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-0.000012f"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_F16) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(Call<f16>(-1.2e-3_h));
@@ -93,7 +93,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float16_t(-0.00119972229h)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Bool) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Bool) {
     WrapInFunction(Call<bool>(true));
 
     GeneratorImpl& gen = Build();
@@ -102,7 +102,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("true"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Int) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Int) {
     WrapInFunction(Call<i32>(-12345_i));
 
     GeneratorImpl& gen = Build();
@@ -111,7 +111,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Uint) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Uint) {
     WrapInFunction(Call<u32>(12345_u));
 
     GeneratorImpl& gen = Build();
@@ -120,7 +120,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("12345u"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_F32) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_F32) {
     WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
 
     GeneratorImpl& gen = Build();
@@ -129,7 +129,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_F16) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
@@ -142,7 +142,7 @@
         HasSubstr("vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h))"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_Empty_F32) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_Empty_F32) {
     WrapInFunction(vec3<f32>());
 
     GeneratorImpl& gen = Build();
@@ -151,7 +151,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("0.0f).xxx"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_Empty_F16) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>());
@@ -162,7 +162,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("(float16_t(0.0h)).xxx"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F32_Literal) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Literal) {
     WrapInFunction(vec3<f32>(2_f));
 
     GeneratorImpl& gen = Build();
@@ -171,7 +171,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("2.0f).xxx"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F16_Literal) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Literal) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(2_h));
@@ -182,7 +182,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("(float16_t(2.0h)).xxx"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F32_Var) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Var) {
     auto* var = Var("v", Expr(2_f));
     auto* cast = vec3<f32>(var);
     WrapInFunction(var, cast);
@@ -194,7 +194,7 @@
   const float3 tint_symbol = float3((v).xxx);)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F16_Var) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Var) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
@@ -208,7 +208,7 @@
   const vector<float16_t, 3> tint_symbol = vector<float16_t, 3>((v).xxx);)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_Bool_Literal) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Bool_Literal) {
     WrapInFunction(vec3<bool>(true));
 
     GeneratorImpl& gen = Build();
@@ -217,7 +217,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("(true).xxx"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_Bool_Var) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Bool_Var) {
     auto* var = Var("v", Expr(true));
     auto* cast = vec3<bool>(var);
     WrapInFunction(var, cast);
@@ -229,7 +229,7 @@
   const bool3 tint_symbol = bool3((v).xxx);)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_Int) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Int) {
     WrapInFunction(vec3<i32>(2_i));
 
     GeneratorImpl& gen = Build();
@@ -238,7 +238,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("2).xxx"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_UInt) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_UInt) {
     WrapInFunction(vec3<u32>(2_u));
 
     GeneratorImpl& gen = Build();
@@ -247,7 +247,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("2u).xxx"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_F32) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_F32) {
     WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
 
     GeneratorImpl& gen = Build();
@@ -258,7 +258,7 @@
                 HasSubstr("float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_F16) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
@@ -273,7 +273,7 @@
                           "3>(float16_t(3.0h), float16_t(4.0h), float16_t(5.0h)))"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Complex_F32) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_Complex_F32) {
     // mat4x4<f32>(
     //     vec4<f32>(2.0f, 3.0f, 4.0f, 8.0f),
     //     vec4<f32>(),
@@ -287,10 +287,10 @@
     auto* vector_identical_init =
         vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
 
-    auto* initializer = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
+    auto* constructor = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
                                     vector_identical_init);
 
-    WrapInFunction(initializer);
+    WrapInFunction(constructor);
 
     GeneratorImpl& gen = Build();
 
@@ -300,7 +300,7 @@
                                         "(7.0f).xxxx, float4(42.0f, 21.0f, 6.0f, -5.0f))"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Complex_F16) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_Complex_F16) {
     // mat4x4<f16>(
     //     vec4<f16>(2.0h, 3.0h, 4.0h, 8.0h),
     //     vec4<f16>(),
@@ -316,10 +316,10 @@
     auto* vector_identical_init =
         vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
 
-    auto* initializer = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
+    auto* constructor = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
                                     vector_identical_init);
 
-    WrapInFunction(initializer);
+    WrapInFunction(constructor);
 
     GeneratorImpl& gen = Build();
 
@@ -333,7 +333,7 @@
                                         "float16_t(6.0h), float16_t(-5.0h)))"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Empty_F32) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_Empty_F32) {
     WrapInFunction(mat2x3<f32>());
 
     GeneratorImpl& gen = Build();
@@ -343,7 +343,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float2x3 tint_symbol = float2x3((0.0f).xxx, (0.0f).xxx)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Empty_F16) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>());
@@ -356,7 +356,7 @@
                 HasSubstr("matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Identity_F32) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_Identity_F32) {
     // fn f() {
     //     var m_1: mat4x4<f32> = mat4x4<f32>();
     //     var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
@@ -374,7 +374,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float4x4 m_2 = float4x4(m_1);"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Identity_F16) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_Identity_F16) {
     // fn f() {
     //     var m_1: mat4x4<f16> = mat4x4<f16>();
     //     var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
@@ -395,7 +395,7 @@
                 HasSubstr("matrix<float16_t, 4, 4> m_2 = matrix<float16_t, 4, 4>(m_1);"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Array) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Array) {
     WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
                         vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
 
@@ -406,7 +406,7 @@
                                         " float3(7.0f, 8.0f, 9.0f)}"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Array_Empty) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Array_Empty) {
     WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u)));
 
     GeneratorImpl& gen = Build();
@@ -415,7 +415,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("(float3[3])0"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Struct) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Struct) {
     auto* str = Structure("S", utils::Vector{
                                    Member("a", ty.i32()),
                                    Member("b", ty.f32()),
@@ -430,7 +430,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("{1, 2.0f, int3(3, 4, 5)}"));
 }
 
-TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Struct_Empty) {
+TEST_F(HlslGeneratorImplTest_Constructor, Type_Struct_Empty) {
     auto* str = Structure("S", utils::Vector{
                                    Member("a", ty.i32()),
                                    Member("b", ty.f32()),
diff --git a/src/tint/writer/hlsl/generator_impl_function_test.cc b/src/tint/writer/hlsl/generator_impl_function_test.cc
index afad67c..fbef3f2 100644
--- a/src/tint/writer/hlsl/generator_impl_function_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_function_test.cc
@@ -101,8 +101,8 @@
     // fn f(foo : ptr<function, f32>) -> f32 {
     //   return *foo;
     // }
-    Func("f", utils::Vector{Param("foo", ty.pointer<f32>(type::AddressSpace::kFunction))}, ty.f32(),
-         utils::Vector{Return(Deref("foo"))});
+    Func("f", utils::Vector{Param("foo", ty.pointer<f32>(builtin::AddressSpace::kFunction))},
+         ty.f32(), utils::Vector{Return(Deref("foo"))});
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -360,7 +360,7 @@
 TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_Uniform) {
     auto* ubo_ty = Structure("UBO", utils::Vector{Member("coord", ty.vec4<f32>())});
     auto* ubo =
-        GlobalVar("ubo", ty.Of(ubo_ty), type::AddressSpace::kUniform, Binding(0_a), Group(1_a));
+        GlobalVar("ubo", ty.Of(ubo_ty), builtin::AddressSpace::kUniform, Binding(0_a), Group(1_a));
 
     Func("sub_func",
          utils::Vector{
@@ -403,7 +403,7 @@
 TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_UniformStruct) {
     auto* s = Structure("Uniforms", utils::Vector{Member("coord", ty.vec4<f32>())});
 
-    GlobalVar("uniforms", ty.Of(s), type::AddressSpace::kUniform, Binding(0_a), Group(1_a));
+    GlobalVar("uniforms", ty.Of(s), builtin::AddressSpace::kUniform, Binding(0_a), Group(1_a));
 
     auto* var = Var("v", ty.f32(), MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
 
@@ -436,7 +436,7 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(1_a));
 
     auto* var = Var("v", ty.f32(), MemberAccessor("coord", "b"));
@@ -469,8 +469,8 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
-              Group(1_a));
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead,
+              Binding(0_a), Group(1_a));
 
     auto* var = Var("v", ty.f32(), MemberAccessor("coord", "b"));
 
@@ -502,7 +502,7 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(1_a));
 
     Func("frag_main", utils::Empty, ty.void_(),
@@ -533,7 +533,7 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(1_a));
 
     Func("frag_main", utils::Empty, ty.void_(),
@@ -560,7 +560,7 @@
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
     auto* s = Structure("S", utils::Vector{Member("x", ty.f32())});
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kUniform, Binding(0_a), Group(1_a));
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kUniform, Binding(0_a), Group(1_a));
 
     Func("sub_func",
          utils::Vector{
@@ -602,7 +602,7 @@
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
     auto* s = Structure("S", utils::Vector{Member("x", ty.f32())});
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(1_a));
 
     Func("sub_func",
@@ -830,7 +830,7 @@
 
     auto* s = Structure("Data", utils::Vector{Member("d", ty.f32())});
 
-    GlobalVar("data", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("data", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(0_a));
 
     {
diff --git a/src/tint/writer/hlsl/generator_impl_identifier_test.cc b/src/tint/writer/hlsl/generator_impl_identifier_test.cc
index c28e757..1e2b47b 100644
--- a/src/tint/writer/hlsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_identifier_test.cc
@@ -20,7 +20,7 @@
 using HlslGeneratorImplTest_Identifier = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Identifier, EmitIdentifierExpression) {
-    GlobalVar("foo", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("foo", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* i = Expr("foo");
     WrapInFunction(i);
diff --git a/src/tint/writer/hlsl/generator_impl_if_test.cc b/src/tint/writer/hlsl/generator_impl_if_test.cc
index c599648..9feb41e 100644
--- a/src/tint/writer/hlsl/generator_impl_if_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_if_test.cc
@@ -20,7 +20,7 @@
 using HlslGeneratorImplTest_If = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_If, Emit_If) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* cond = Expr("cond");
     auto* body = Block(Return());
@@ -38,8 +38,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElseIf) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("else_cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("else_cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_cond = Expr("else_cond");
     auto* else_body = Block(Return());
@@ -65,7 +65,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElse) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_body = Block(Return());
 
@@ -88,8 +88,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_If, Emit_IfWithMultiple) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("else_cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("else_cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_cond = Expr("else_cond");
 
diff --git a/src/tint/writer/hlsl/generator_impl_import_test.cc b/src/tint/writer/hlsl/generator_impl_import_test.cc
index de864c4..425c663 100644
--- a/src/tint/writer/hlsl/generator_impl_import_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_import_test.cc
@@ -252,7 +252,7 @@
                          testing::Values(HlslImportData{"clamp", "clamp"}));
 
 TEST_F(HlslGeneratorImplTest_Import, HlslImportData_Determinant) {
-    GlobalVar("var", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("determinant", "var");
     WrapInFunction(expr);
@@ -265,7 +265,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Import, HlslImportData_QuantizeToF16_Scalar) {
-    GlobalVar("v", Expr(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", Expr(2_f), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("quantizeToF16", "v");
     WrapInFunction(expr);
@@ -278,7 +278,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Import, HlslImportData_QuantizeToF16_Vector) {
-    GlobalVar("v", vec3<f32>(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec3<f32>(2_f), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("quantizeToF16", "v");
     WrapInFunction(expr);
diff --git a/src/tint/writer/hlsl/generator_impl_loop_test.cc b/src/tint/writer/hlsl/generator_impl_loop_test.cc
index 620543d..45bf04a 100644
--- a/src/tint/writer/hlsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_loop_test.cc
@@ -93,8 +93,8 @@
 TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopNestedWithContinuing) {
     Func("a_statement", {}, ty.void_(), {});
 
-    GlobalVar("lhs", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("rhs", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("lhs", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
@@ -142,7 +142,7 @@
     //   }
     // }
 
-    GlobalVar("rhs", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4_f))),  //
                        Decl(Var("other", ty.f32())),             //
diff --git a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
index f2607c5..ca08714 100644
--- a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -93,16 +93,16 @@
         ProgramBuilder& b = *this;
         auto* s = b.Structure("Data", members);
 
-        b.GlobalVar("data", b.ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
-                    b.Group(1_a), b.Binding(0_a));
+        b.GlobalVar("data", b.ty.Of(s), builtin::AddressSpace::kStorage,
+                    builtin::Access::kReadWrite, b.Group(1_a), b.Binding(0_a));
     }
 
     void SetupUniformBuffer(utils::VectorRef<const ast::StructMember*> members) {
         ProgramBuilder& b = *this;
         auto* s = b.Structure("Data", members);
 
-        b.GlobalVar("data", b.ty.Of(s), type::AddressSpace::kUniform, type::Access::kUndefined,
-                    b.Group(1_a), b.Binding(1_a));
+        b.GlobalVar("data", b.ty.Of(s), builtin::AddressSpace::kUniform,
+                    builtin::Access::kUndefined, b.Group(1_a), b.Binding(1_a));
     }
 
     void SetupFunction(utils::VectorRef<const ast::Statement*> statements) {
@@ -122,7 +122,7 @@
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
     auto* s = Structure("Data", utils::Vector{Member("mem", ty.f32())});
-    GlobalVar("str", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("str", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     auto* expr = MemberAccessor("str", "mem");
     WrapInFunction(Var("expr", ty.f32(), expr));
@@ -202,86 +202,86 @@
                     TypeCase{ty_vec4<i32>, "asint(data.Load4(16u))"},
                     TypeCase{ty_vec4<f16>, "data.Load<vector<float16_t, 4> >(8u)"},
                     TypeCase{ty_mat2x2<f32>,
-                             "return float2x2(asfloat(buffer.Load2((offset + 0u))), "
-                             "asfloat(buffer.Load2((offset + 8u))));"},
+                             "return float2x2(asfloat(data.Load2((offset + 0u))), "
+                             "asfloat(data.Load2((offset + 8u))));"},
                     TypeCase{ty_mat2x3<f32>,
-                             "return float2x3(asfloat(buffer.Load3((offset + 0u))), "
-                             "asfloat(buffer.Load3((offset + 16u))));"},
+                             "return float2x3(asfloat(data.Load3((offset + 0u))), "
+                             "asfloat(data.Load3((offset + 16u))));"},
                     TypeCase{ty_mat2x4<f32>,
-                             "return float2x4(asfloat(buffer.Load4((offset + 0u))), "
-                             "asfloat(buffer.Load4((offset + 16u))));"},
+                             "return float2x4(asfloat(data.Load4((offset + 0u))), "
+                             "asfloat(data.Load4((offset + 16u))));"},
                     TypeCase{ty_mat3x2<f32>,
-                             "return float3x2(asfloat(buffer.Load2((offset + 0u))), "
-                             "asfloat(buffer.Load2((offset + 8u))), "
-                             "asfloat(buffer.Load2((offset + 16u))));"},
+                             "return float3x2(asfloat(data.Load2((offset + 0u))), "
+                             "asfloat(data.Load2((offset + 8u))), "
+                             "asfloat(data.Load2((offset + 16u))));"},
                     TypeCase{ty_mat3x3<f32>,
-                             "return float3x3(asfloat(buffer.Load3((offset + 0u))), "
-                             "asfloat(buffer.Load3((offset + 16u))), "
-                             "asfloat(buffer.Load3((offset + 32u))));"},
+                             "return float3x3(asfloat(data.Load3((offset + 0u))), "
+                             "asfloat(data.Load3((offset + 16u))), "
+                             "asfloat(data.Load3((offset + 32u))));"},
                     TypeCase{ty_mat3x4<f32>,
-                             "return float3x4(asfloat(buffer.Load4((offset + 0u))), "
-                             "asfloat(buffer.Load4((offset + 16u))), "
-                             "asfloat(buffer.Load4((offset + 32u))));"},
+                             "return float3x4(asfloat(data.Load4((offset + 0u))), "
+                             "asfloat(data.Load4((offset + 16u))), "
+                             "asfloat(data.Load4((offset + 32u))));"},
                     TypeCase{ty_mat4x2<f32>,
-                             "return float4x2(asfloat(buffer.Load2((offset + 0u))), "
-                             "asfloat(buffer.Load2((offset + 8u))), "
-                             "asfloat(buffer.Load2((offset + 16u))), "
-                             "asfloat(buffer.Load2((offset + 24u))));"},
+                             "return float4x2(asfloat(data.Load2((offset + 0u))), "
+                             "asfloat(data.Load2((offset + 8u))), "
+                             "asfloat(data.Load2((offset + 16u))), "
+                             "asfloat(data.Load2((offset + 24u))));"},
                     TypeCase{ty_mat4x3<f32>,
-                             "return float4x3(asfloat(buffer.Load3((offset + 0u))), "
-                             "asfloat(buffer.Load3((offset + 16u))), "
-                             "asfloat(buffer.Load3((offset + 32u))), "
-                             "asfloat(buffer.Load3((offset + 48u))));"},
+                             "return float4x3(asfloat(data.Load3((offset + 0u))), "
+                             "asfloat(data.Load3((offset + 16u))), "
+                             "asfloat(data.Load3((offset + 32u))), "
+                             "asfloat(data.Load3((offset + 48u))));"},
                     TypeCase{ty_mat4x4<f32>,
-                             "return float4x4(asfloat(buffer.Load4((offset + 0u))), "
-                             "asfloat(buffer.Load4((offset + 16u))), "
-                             "asfloat(buffer.Load4((offset + 32u))), "
-                             "asfloat(buffer.Load4((offset + 48u))));"},
+                             "return float4x4(asfloat(data.Load4((offset + 0u))), "
+                             "asfloat(data.Load4((offset + 16u))), "
+                             "asfloat(data.Load4((offset + 32u))), "
+                             "asfloat(data.Load4((offset + 48u))));"},
                     TypeCase{ty_mat2x2<f16>,
                              "return matrix<float16_t, 2, 2>("
-                             "buffer.Load<vector<float16_t, 2> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 2> >((offset + 4u)));"},
+                             "data.Load<vector<float16_t, 2> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 2> >((offset + 4u)));"},
                     TypeCase{ty_mat2x3<f16>,
                              "return matrix<float16_t, 2, 3>("
-                             "buffer.Load<vector<float16_t, 3> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 3> >((offset + 8u)));"},
+                             "data.Load<vector<float16_t, 3> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 3> >((offset + 8u)));"},
                     TypeCase{ty_mat2x4<f16>,
                              "return matrix<float16_t, 2, 4>("
-                             "buffer.Load<vector<float16_t, 4> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 4> >((offset + 8u)));"},
+                             "data.Load<vector<float16_t, 4> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 4> >((offset + 8u)));"},
                     TypeCase{ty_mat3x2<f16>,
                              "return matrix<float16_t, 3, 2>("
-                             "buffer.Load<vector<float16_t, 2> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 2> >((offset + 4u)), "
-                             "buffer.Load<vector<float16_t, 2> >((offset + 8u)));"},
+                             "data.Load<vector<float16_t, 2> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 2> >((offset + 4u)), "
+                             "data.Load<vector<float16_t, 2> >((offset + 8u)));"},
                     TypeCase{ty_mat3x3<f16>,
                              "return matrix<float16_t, 3, 3>("
-                             "buffer.Load<vector<float16_t, 3> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 3> >((offset + 8u)), "
-                             "buffer.Load<vector<float16_t, 3> >((offset + 16u)));"},
+                             "data.Load<vector<float16_t, 3> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 3> >((offset + 8u)), "
+                             "data.Load<vector<float16_t, 3> >((offset + 16u)));"},
                     TypeCase{ty_mat3x4<f16>,
                              "return matrix<float16_t, 3, 4>("
-                             "buffer.Load<vector<float16_t, 4> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 4> >((offset + 8u)), "
-                             "buffer.Load<vector<float16_t, 4> >((offset + 16u)));"},
+                             "data.Load<vector<float16_t, 4> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 4> >((offset + 8u)), "
+                             "data.Load<vector<float16_t, 4> >((offset + 16u)));"},
                     TypeCase{ty_mat4x2<f16>,
                              "return matrix<float16_t, 4, 2>("
-                             "buffer.Load<vector<float16_t, 2> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 2> >((offset + 4u)), "
-                             "buffer.Load<vector<float16_t, 2> >((offset + 8u)), "
-                             "buffer.Load<vector<float16_t, 2> >((offset + 12u)));"},
+                             "data.Load<vector<float16_t, 2> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 2> >((offset + 4u)), "
+                             "data.Load<vector<float16_t, 2> >((offset + 8u)), "
+                             "data.Load<vector<float16_t, 2> >((offset + 12u)));"},
                     TypeCase{ty_mat4x3<f16>,
                              "return matrix<float16_t, 4, 3>("
-                             "buffer.Load<vector<float16_t, 3> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 3> >((offset + 8u)), "
-                             "buffer.Load<vector<float16_t, 3> >((offset + 16u)), "
-                             "buffer.Load<vector<float16_t, 3> >((offset + 24u)));"},
+                             "data.Load<vector<float16_t, 3> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 3> >((offset + 8u)), "
+                             "data.Load<vector<float16_t, 3> >((offset + 16u)), "
+                             "data.Load<vector<float16_t, 3> >((offset + 24u)));"},
                     TypeCase{ty_mat4x4<f16>,
                              "return matrix<float16_t, 4, 4>("
-                             "buffer.Load<vector<float16_t, 4> >((offset + 0u)), "
-                             "buffer.Load<vector<float16_t, 4> >((offset + 8u)), "
-                             "buffer.Load<vector<float16_t, 4> >((offset + 16u)), "
-                             "buffer.Load<vector<float16_t, 4> >((offset + 24u)));"}));
+                             "data.Load<vector<float16_t, 4> >((offset + 0u)), "
+                             "data.Load<vector<float16_t, 4> >((offset + 8u)), "
+                             "data.Load<vector<float16_t, 4> >((offset + 16u)), "
+                             "data.Load<vector<float16_t, 4> >((offset + 24u)));"}));
 
 using HlslGeneratorImplTest_MemberAccessor_StorageBufferLoad_DynamicOffset =
     HlslGeneratorImplTest_MemberAccessorWithParam<TypeCase>;
@@ -346,86 +346,86 @@
         TypeCase{ty_vec4<i32>, "asint(data.Load4(((48u * uint(i)) + 16u)))"},
         TypeCase{ty_vec4<f16>, "data.Load<vector<float16_t, 4> >(((32u * uint(i)) + 8u))"},
         TypeCase{ty_mat2x2<f32>,
-                 "return float2x2(asfloat(buffer.Load2((offset + 0u))), "
-                 "asfloat(buffer.Load2((offset + 8u))));"},
+                 "return float2x2(asfloat(data.Load2((offset + 0u))), "
+                 "asfloat(data.Load2((offset + 8u))));"},
         TypeCase{ty_mat2x3<f32>,
-                 "return float2x3(asfloat(buffer.Load3((offset + 0u))), "
-                 "asfloat(buffer.Load3((offset + 16u))));"},
+                 "return float2x3(asfloat(data.Load3((offset + 0u))), "
+                 "asfloat(data.Load3((offset + 16u))));"},
         TypeCase{ty_mat2x4<f32>,
-                 "return float2x4(asfloat(buffer.Load4((offset + 0u))), "
-                 "asfloat(buffer.Load4((offset + 16u))));"},
+                 "return float2x4(asfloat(data.Load4((offset + 0u))), "
+                 "asfloat(data.Load4((offset + 16u))));"},
         TypeCase{ty_mat3x2<f32>,
-                 "return float3x2(asfloat(buffer.Load2((offset + 0u))), "
-                 "asfloat(buffer.Load2((offset + 8u))), "
-                 "asfloat(buffer.Load2((offset + 16u))));"},
+                 "return float3x2(asfloat(data.Load2((offset + 0u))), "
+                 "asfloat(data.Load2((offset + 8u))), "
+                 "asfloat(data.Load2((offset + 16u))));"},
         TypeCase{ty_mat3x3<f32>,
-                 "return float3x3(asfloat(buffer.Load3((offset + 0u))), "
-                 "asfloat(buffer.Load3((offset + 16u))), "
-                 "asfloat(buffer.Load3((offset + 32u))));"},
+                 "return float3x3(asfloat(data.Load3((offset + 0u))), "
+                 "asfloat(data.Load3((offset + 16u))), "
+                 "asfloat(data.Load3((offset + 32u))));"},
         TypeCase{ty_mat3x4<f32>,
-                 "return float3x4(asfloat(buffer.Load4((offset + 0u))), "
-                 "asfloat(buffer.Load4((offset + 16u))), "
-                 "asfloat(buffer.Load4((offset + 32u))));"},
+                 "return float3x4(asfloat(data.Load4((offset + 0u))), "
+                 "asfloat(data.Load4((offset + 16u))), "
+                 "asfloat(data.Load4((offset + 32u))));"},
         TypeCase{ty_mat4x2<f32>,
-                 "return float4x2(asfloat(buffer.Load2((offset + 0u))), "
-                 "asfloat(buffer.Load2((offset + 8u))), "
-                 "asfloat(buffer.Load2((offset + 16u))), "
-                 "asfloat(buffer.Load2((offset + 24u))));"},
+                 "return float4x2(asfloat(data.Load2((offset + 0u))), "
+                 "asfloat(data.Load2((offset + 8u))), "
+                 "asfloat(data.Load2((offset + 16u))), "
+                 "asfloat(data.Load2((offset + 24u))));"},
         TypeCase{ty_mat4x3<f32>,
-                 "return float4x3(asfloat(buffer.Load3((offset + 0u))), "
-                 "asfloat(buffer.Load3((offset + 16u))), "
-                 "asfloat(buffer.Load3((offset + 32u))), "
-                 "asfloat(buffer.Load3((offset + 48u))));"},
+                 "return float4x3(asfloat(data.Load3((offset + 0u))), "
+                 "asfloat(data.Load3((offset + 16u))), "
+                 "asfloat(data.Load3((offset + 32u))), "
+                 "asfloat(data.Load3((offset + 48u))));"},
         TypeCase{ty_mat4x4<f32>,
-                 "return float4x4(asfloat(buffer.Load4((offset + 0u))), "
-                 "asfloat(buffer.Load4((offset + 16u))), "
-                 "asfloat(buffer.Load4((offset + 32u))), "
-                 "asfloat(buffer.Load4((offset + 48u))));"},
+                 "return float4x4(asfloat(data.Load4((offset + 0u))), "
+                 "asfloat(data.Load4((offset + 16u))), "
+                 "asfloat(data.Load4((offset + 32u))), "
+                 "asfloat(data.Load4((offset + 48u))));"},
         TypeCase{ty_mat2x2<f16>,
                  "return matrix<float16_t, 2, 2>("
-                 "buffer.Load<vector<float16_t, 2> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 2> >((offset + 4u)));"},
+                 "data.Load<vector<float16_t, 2> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 2> >((offset + 4u)));"},
         TypeCase{ty_mat2x3<f16>,
                  "return matrix<float16_t, 2, 3>("
-                 "buffer.Load<vector<float16_t, 3> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 3> >((offset + 8u)));"},
+                 "data.Load<vector<float16_t, 3> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 3> >((offset + 8u)));"},
         TypeCase{ty_mat2x4<f16>,
                  "return matrix<float16_t, 2, 4>("
-                 "buffer.Load<vector<float16_t, 4> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 4> >((offset + 8u)));"},
+                 "data.Load<vector<float16_t, 4> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 4> >((offset + 8u)));"},
         TypeCase{ty_mat3x2<f16>,
                  "return matrix<float16_t, 3, 2>("
-                 "buffer.Load<vector<float16_t, 2> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 2> >((offset + 4u)), "
-                 "buffer.Load<vector<float16_t, 2> >((offset + 8u)));"},
+                 "data.Load<vector<float16_t, 2> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 2> >((offset + 4u)), "
+                 "data.Load<vector<float16_t, 2> >((offset + 8u)));"},
         TypeCase{ty_mat3x3<f16>,
                  "return matrix<float16_t, 3, 3>("
-                 "buffer.Load<vector<float16_t, 3> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 3> >((offset + 8u)), "
-                 "buffer.Load<vector<float16_t, 3> >((offset + 16u)));"},
+                 "data.Load<vector<float16_t, 3> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 3> >((offset + 8u)), "
+                 "data.Load<vector<float16_t, 3> >((offset + 16u)));"},
         TypeCase{ty_mat3x4<f16>,
                  "return matrix<float16_t, 3, 4>("
-                 "buffer.Load<vector<float16_t, 4> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 4> >((offset + 8u)), "
-                 "buffer.Load<vector<float16_t, 4> >((offset + 16u)));"},
+                 "data.Load<vector<float16_t, 4> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 4> >((offset + 8u)), "
+                 "data.Load<vector<float16_t, 4> >((offset + 16u)));"},
         TypeCase{ty_mat4x2<f16>,
                  "return matrix<float16_t, 4, 2>("
-                 "buffer.Load<vector<float16_t, 2> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 2> >((offset + 4u)), "
-                 "buffer.Load<vector<float16_t, 2> >((offset + 8u)), "
-                 "buffer.Load<vector<float16_t, 2> >((offset + 12u)));"},
+                 "data.Load<vector<float16_t, 2> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 2> >((offset + 4u)), "
+                 "data.Load<vector<float16_t, 2> >((offset + 8u)), "
+                 "data.Load<vector<float16_t, 2> >((offset + 12u)));"},
         TypeCase{ty_mat4x3<f16>,
                  "return matrix<float16_t, 4, 3>("
-                 "buffer.Load<vector<float16_t, 3> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 3> >((offset + 8u)), "
-                 "buffer.Load<vector<float16_t, 3> >((offset + 16u)), "
-                 "buffer.Load<vector<float16_t, 3> >((offset + 24u)));"},
+                 "data.Load<vector<float16_t, 3> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 3> >((offset + 8u)), "
+                 "data.Load<vector<float16_t, 3> >((offset + 16u)), "
+                 "data.Load<vector<float16_t, 3> >((offset + 24u)));"},
         TypeCase{ty_mat4x4<f16>,
                  "return matrix<float16_t, 4, 4>("
-                 "buffer.Load<vector<float16_t, 4> >((offset + 0u)), "
-                 "buffer.Load<vector<float16_t, 4> >((offset + 8u)), "
-                 "buffer.Load<vector<float16_t, 4> >((offset + 16u)), "
-                 "buffer.Load<vector<float16_t, 4> >((offset + 24u)));"}));
+                 "data.Load<vector<float16_t, 4> >((offset + 0u)), "
+                 "data.Load<vector<float16_t, 4> >((offset + 8u)), "
+                 "data.Load<vector<float16_t, 4> >((offset + 16u)), "
+                 "data.Load<vector<float16_t, 4> >((offset + 24u)));"}));
 
 using HlslGeneratorImplTest_MemberAccessor_UniformBufferLoad_ConstantOffset =
     HlslGeneratorImplTest_MemberAccessorWithParam<TypeCase>;
@@ -483,207 +483,207 @@
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
   vector<float16_t, 4> x = vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]);)"},
-                    TypeCase{ty_mat2x2<f32>, R"(float2x2 tint_symbol(uint4 buffer[2], uint offset) {
+                    TypeCase{ty_mat2x2<f32>, R"(float2x2 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
+  uint4 ubo_load = data[scalar_offset / 4];
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_1 = data[scalar_offset_1 / 4];
   return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
 })"},
-                    TypeCase{ty_mat2x3<f32>, R"(float2x3 tint_symbol(uint4 buffer[3], uint offset) {
+                    TypeCase{ty_mat2x3<f32>, R"(float2x3 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
-  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+  return float2x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz));
 })"},
-                    TypeCase{ty_mat2x4<f32>, R"(float2x4 tint_symbol(uint4 buffer[3], uint offset) {
+                    TypeCase{ty_mat2x4<f32>, R"(float2x4 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
-  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+  return float2x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]));
 })"},
-                    TypeCase{ty_mat3x2<f32>, R"(float3x2 tint_symbol(uint4 buffer[2], uint offset) {
+                    TypeCase{ty_mat3x2<f32>, R"(float3x2 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
+  uint4 ubo_load = data[scalar_offset / 4];
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_1 = data[scalar_offset_1 / 4];
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_2 = data[scalar_offset_2 / 4];
   return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
 })"},
-                    TypeCase{ty_mat3x3<f32>, R"(float3x3 tint_symbol(uint4 buffer[4], uint offset) {
+                    TypeCase{ty_mat3x3<f32>, R"(float3x3 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
-  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+  return float3x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz), asfloat(data[scalar_offset_2 / 4].xyz));
 })"},
-                    TypeCase{ty_mat3x4<f32>, R"(float3x4 tint_symbol(uint4 buffer[4], uint offset) {
+                    TypeCase{ty_mat3x4<f32>, R"(float3x4 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
-  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+  return float3x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]), asfloat(data[scalar_offset_2 / 4]));
 })"},
-                    TypeCase{ty_mat4x2<f32>, R"(float4x2 tint_symbol(uint4 buffer[3], uint offset) {
+                    TypeCase{ty_mat4x2<f32>, R"(float4x2 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
+  uint4 ubo_load = data[scalar_offset / 4];
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_1 = data[scalar_offset_1 / 4];
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_2 = data[scalar_offset_2 / 4];
   const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_3 / 4];
   return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
 })"},
-                    TypeCase{ty_mat4x3<f32>, R"(float4x3 tint_symbol(uint4 buffer[5], uint offset) {
+                    TypeCase{ty_mat4x3<f32>, R"(float4x3 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
   const uint scalar_offset_3 = ((offset + 48u)) / 4;
-  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+  return float4x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz), asfloat(data[scalar_offset_2 / 4].xyz), asfloat(data[scalar_offset_3 / 4].xyz));
 })"},
-                    TypeCase{ty_mat4x4<f32>, R"(float4x4 tint_symbol(uint4 buffer[5], uint offset) {
+                    TypeCase{ty_mat4x4<f32>, R"(float4x4 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
   const uint scalar_offset_3 = ((offset + 48u)) / 4;
-  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+  return float4x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]), asfloat(data[scalar_offset_2 / 4]), asfloat(data[scalar_offset_3 / 4]));
 })"},
                     TypeCase{ty_mat2x2<f16>,
-                             R"(matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+                             R"(matrix<float16_t, 2, 2> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
   const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
   return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
 })"},
                     TypeCase{ty_mat2x3<f16>,
-                             R"(matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[2], uint offset) {
+                             R"(matrix<float16_t, 2, 3> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
   return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
 })"},
                     TypeCase{ty_mat2x4<f16>,
-                             R"(matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[2], uint offset) {
+                             R"(matrix<float16_t, 2, 4> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
   return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
 })"},
                     TypeCase{ty_mat3x2<f16>,
-                             R"(matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+                             R"(matrix<float16_t, 3, 2> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
   const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
   const uint scalar_offset_2 = ((offset + 8u)) / 4;
-  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  uint ubo_load_2 = data[scalar_offset_2 / 4][scalar_offset_2 % 4];
   return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
 })"},
                     TypeCase{ty_mat3x3<f16>,
-                             R"(matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+                             R"(matrix<float16_t, 3, 3> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_5 = data[scalar_offset_2 / 4];
   uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
   vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
   float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
   return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
 })"},
                     TypeCase{ty_mat3x4<f16>,
-                             R"(matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+                             R"(matrix<float16_t, 3, 4> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_5 = data[scalar_offset_2 / 4];
   uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
   vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
   vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
   return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));)"},
                     TypeCase{ty_mat4x2<f16>,
-                             R"(matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[2], uint offset) {
+                             R"(matrix<float16_t, 4, 2> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
   const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
   const uint scalar_offset_2 = ((offset + 8u)) / 4;
-  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  uint ubo_load_2 = data[scalar_offset_2 / 4][scalar_offset_2 % 4];
   const uint scalar_offset_3 = ((offset + 12u)) / 4;
-  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  uint ubo_load_3 = data[scalar_offset_3 / 4][scalar_offset_3 % 4];
   return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
 })"},
                     TypeCase{ty_mat4x3<f16>,
-                             R"(matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[3], uint offset) {
+                             R"(matrix<float16_t, 4, 3> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_5 = data[scalar_offset_2 / 4];
   uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
   vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
   float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
   const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint4 ubo_load_7 = data[scalar_offset_3 / 4];
   uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
   vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
   float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
   return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
 })"},
                     TypeCase{ty_mat4x4<f16>,
-                             R"(matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[3], uint offset) {
+                             R"(matrix<float16_t, 4, 4> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_5 = data[scalar_offset_2 / 4];
   uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
   vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
   vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
   const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint4 ubo_load_7 = data[scalar_offset_3 / 4];
   uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
   vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
   vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
@@ -769,208 +769,208 @@
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
   vector<float16_t, 4> x = vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]);)"},
-        TypeCase{ty_mat2x2<f32>, R"(float2x2 tint_symbol(uint4 buffer[12], uint offset) {
+        TypeCase{ty_mat2x2<f32>, R"(float2x2 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
+  uint4 ubo_load = data[scalar_offset / 4];
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_1 = data[scalar_offset_1 / 4];
   return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
 })"},
-        TypeCase{ty_mat2x3<f32>, R"(float2x3 tint_symbol(uint4 buffer[16], uint offset) {
+        TypeCase{ty_mat2x3<f32>, R"(float2x3 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
-  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+  return float2x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz));
 })"},
-        TypeCase{ty_mat2x4<f32>, R"(float2x4 tint_symbol(uint4 buffer[16], uint offset) {
+        TypeCase{ty_mat2x4<f32>, R"(float2x4 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
-  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+  return float2x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]));
 })"},
-        TypeCase{ty_mat3x2<f32>, R"(float3x2 tint_symbol(uint4 buffer[12], uint offset) {
+        TypeCase{ty_mat3x2<f32>, R"(float3x2 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
+  uint4 ubo_load = data[scalar_offset / 4];
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_1 = data[scalar_offset_1 / 4];
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_2 = data[scalar_offset_2 / 4];
   return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
 })"},
-        TypeCase{ty_mat3x3<f32>, R"(float3x3 tint_symbol(uint4 buffer[20], uint offset) {
+        TypeCase{ty_mat3x3<f32>, R"(float3x3 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
-  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+  return float3x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz), asfloat(data[scalar_offset_2 / 4].xyz));
 })"},
-        TypeCase{ty_mat3x4<f32>, R"(float3x4 tint_symbol(uint4 buffer[20], uint offset) {
+        TypeCase{ty_mat3x4<f32>, R"(float3x4 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
-  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+  return float3x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]), asfloat(data[scalar_offset_2 / 4]));
 })"},
-        TypeCase{ty_mat4x2<f32>, R"(float4x2 tint_symbol(uint4 buffer[16], uint offset) {
+        TypeCase{ty_mat4x2<f32>, R"(float4x2 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
+  uint4 ubo_load = data[scalar_offset / 4];
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_1 = data[scalar_offset_1 / 4];
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_2 = data[scalar_offset_2 / 4];
   const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_3 / 4];
   return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
 })"},
-        TypeCase{ty_mat4x3<f32>, R"(float4x3 tint_symbol(uint4 buffer[24], uint offset) {
+        TypeCase{ty_mat4x3<f32>, R"(float4x3 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
   const uint scalar_offset_3 = ((offset + 48u)) / 4;
-  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+  return float4x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz), asfloat(data[scalar_offset_2 / 4].xyz), asfloat(data[scalar_offset_3 / 4].xyz));
 })"},
-        TypeCase{ty_mat4x4<f32>, R"(float4x4 tint_symbol(uint4 buffer[24], uint offset) {
+        TypeCase{ty_mat4x4<f32>, R"(float4x4 data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
   const uint scalar_offset_3 = ((offset + 48u)) / 4;
-  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+  return float4x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]), asfloat(data[scalar_offset_2 / 4]), asfloat(data[scalar_offset_3 / 4]));
 })"},
         TypeCase{ty_mat2x2<f16>,
-                 R"(matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[8], uint offset) {
+                 R"(matrix<float16_t, 2, 2> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
   const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
   return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
 })"},
         TypeCase{ty_mat2x3<f16>,
-                 R"(matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[12], uint offset) {
+                 R"(matrix<float16_t, 2, 3> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
   return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
 })"},
         TypeCase{ty_mat2x4<f16>,
-                 R"(matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[12], uint offset) {
+                 R"(matrix<float16_t, 2, 4> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
   return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
 })"},
         TypeCase{ty_mat3x2<f16>,
-                 R"(matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[8], uint offset) {
+                 R"(matrix<float16_t, 3, 2> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
   const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
   const uint scalar_offset_2 = ((offset + 8u)) / 4;
-  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  uint ubo_load_2 = data[scalar_offset_2 / 4][scalar_offset_2 % 4];
   return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
 })"},
         TypeCase{ty_mat3x3<f16>,
-                 R"(matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[12], uint offset) {
+                 R"(matrix<float16_t, 3, 3> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_5 = data[scalar_offset_2 / 4];
   uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
   vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
   float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
   return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
 })"},
         TypeCase{ty_mat3x4<f16>,
-                 R"(matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[12], uint offset) {
+                 R"(matrix<float16_t, 3, 4> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_5 = data[scalar_offset_2 / 4];
   uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
   vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
   vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
   return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
 })"},
         TypeCase{ty_mat4x2<f16>,
-                 R"(matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[12], uint offset) {
+                 R"(matrix<float16_t, 4, 2> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
   const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
   const uint scalar_offset_2 = ((offset + 8u)) / 4;
-  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  uint ubo_load_2 = data[scalar_offset_2 / 4][scalar_offset_2 % 4];
   const uint scalar_offset_3 = ((offset + 12u)) / 4;
-  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  uint ubo_load_3 = data[scalar_offset_3 / 4][scalar_offset_3 % 4];
   return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
 })"},
         TypeCase{ty_mat4x3<f16>,
-                 R"(matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[16], uint offset) {
+                 R"(matrix<float16_t, 4, 3> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_5 = data[scalar_offset_2 / 4];
   uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
   vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
   float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
   const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint4 ubo_load_7 = data[scalar_offset_3 / 4];
   uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
   vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
   float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
   return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
 })"},
         TypeCase{ty_mat4x4<f16>,
-                 R"(matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[16], uint offset) {
+                 R"(matrix<float16_t, 4, 4> data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint4 ubo_load_1 = data[scalar_offset / 4];
   uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
   vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
   vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
   const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint4 ubo_load_3 = data[scalar_offset_1 / 4];
   uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
   vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
   vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
   const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint4 ubo_load_5 = data[scalar_offset_2 / 4];
   uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
   vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
   vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
   const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint4 ubo_load_7 = data[scalar_offset_3 / 4];
   uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
   vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
   vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
@@ -1026,95 +1026,97 @@
                     TypeCase{ty_vec4<f32>, "data.Store4(16u, asuint(value))"},
                     TypeCase{ty_vec4<i32>, "data.Store4(16u, asuint(value))"},
                     TypeCase{ty_vec4<f16>, "data.Store<vector<float16_t, 4> >(8u, value)"},
-                    TypeCase{ty_mat2x2<f32>, R"({
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
+                    TypeCase{ty_mat2x2<f32>, R"(
+
+void data_store(uint offset, float2x2 value) {
+  data.Store2((offset + 0u), asuint(value[0u]));
+  data.Store2((offset + 8u), asuint(value[1u]));
 })"},
                     TypeCase{ty_mat2x3<f32>, R"({
-  buffer.Store3((offset + 0u), asuint(value[0u]));
-  buffer.Store3((offset + 16u), asuint(value[1u]));
+  data.Store3((offset + 0u), asuint(value[0u]));
+  data.Store3((offset + 16u), asuint(value[1u]));
 })"},
                     TypeCase{ty_mat2x4<f32>, R"({
-  buffer.Store4((offset + 0u), asuint(value[0u]));
-  buffer.Store4((offset + 16u), asuint(value[1u]));
+  data.Store4((offset + 0u), asuint(value[0u]));
+  data.Store4((offset + 16u), asuint(value[1u]));
 })"},
                     TypeCase{ty_mat3x2<f32>, R"({
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
-  buffer.Store2((offset + 16u), asuint(value[2u]));
+  data.Store2((offset + 0u), asuint(value[0u]));
+  data.Store2((offset + 8u), asuint(value[1u]));
+  data.Store2((offset + 16u), asuint(value[2u]));
 })"},
                     TypeCase{ty_mat3x3<f32>, R"({
-  buffer.Store3((offset + 0u), asuint(value[0u]));
-  buffer.Store3((offset + 16u), asuint(value[1u]));
-  buffer.Store3((offset + 32u), asuint(value[2u]));
+  data.Store3((offset + 0u), asuint(value[0u]));
+  data.Store3((offset + 16u), asuint(value[1u]));
+  data.Store3((offset + 32u), asuint(value[2u]));
 })"},
                     TypeCase{ty_mat3x4<f32>, R"({
-  buffer.Store4((offset + 0u), asuint(value[0u]));
-  buffer.Store4((offset + 16u), asuint(value[1u]));
-  buffer.Store4((offset + 32u), asuint(value[2u]));
+  data.Store4((offset + 0u), asuint(value[0u]));
+  data.Store4((offset + 16u), asuint(value[1u]));
+  data.Store4((offset + 32u), asuint(value[2u]));
 })"},
                     TypeCase{ty_mat4x2<f32>, R"({
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
-  buffer.Store2((offset + 16u), asuint(value[2u]));
-  buffer.Store2((offset + 24u), asuint(value[3u]));
+  data.Store2((offset + 0u), asuint(value[0u]));
+  data.Store2((offset + 8u), asuint(value[1u]));
+  data.Store2((offset + 16u), asuint(value[2u]));
+  data.Store2((offset + 24u), asuint(value[3u]));
 })"},
                     TypeCase{ty_mat4x3<f32>, R"({
-  buffer.Store3((offset + 0u), asuint(value[0u]));
-  buffer.Store3((offset + 16u), asuint(value[1u]));
-  buffer.Store3((offset + 32u), asuint(value[2u]));
-  buffer.Store3((offset + 48u), asuint(value[3u]));
+  data.Store3((offset + 0u), asuint(value[0u]));
+  data.Store3((offset + 16u), asuint(value[1u]));
+  data.Store3((offset + 32u), asuint(value[2u]));
+  data.Store3((offset + 48u), asuint(value[3u]));
 })"},
                     TypeCase{ty_mat4x4<f32>, R"({
-  buffer.Store4((offset + 0u), asuint(value[0u]));
-  buffer.Store4((offset + 16u), asuint(value[1u]));
-  buffer.Store4((offset + 32u), asuint(value[2u]));
-  buffer.Store4((offset + 48u), asuint(value[3u]));
+  data.Store4((offset + 0u), asuint(value[0u]));
+  data.Store4((offset + 16u), asuint(value[1u]));
+  data.Store4((offset + 32u), asuint(value[2u]));
+  data.Store4((offset + 48u), asuint(value[3u]));
 })"},
                     TypeCase{ty_mat2x2<f16>, R"({
-  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  data.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
 })"},
                     TypeCase{ty_mat2x3<f16>, R"({
-  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  data.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
 })"},
                     TypeCase{ty_mat2x4<f16>, R"({
-  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  data.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
 })"},
                     TypeCase{ty_mat3x2<f16>, R"({
-  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
-  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  data.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  data.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
 })"},
                     TypeCase{ty_mat3x3<f16>, R"({
-  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
-  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  data.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  data.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
 })"},
                     TypeCase{ty_mat3x4<f16>, R"({
-  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
-  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  data.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  data.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
 })"},
                     TypeCase{ty_mat4x2<f16>, R"({
-  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
-  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
-  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+  data.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  data.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  data.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
 })"},
                     TypeCase{ty_mat4x3<f16>, R"({
-  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
-  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
-  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+  data.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  data.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  data.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
 })"},
                     TypeCase{ty_mat4x4<f16>, R"({
-  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
-  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
-  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
-  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+  data.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  data.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  data.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  data.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
 })"}));
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Matrix_Empty) {
@@ -1140,13 +1142,13 @@
     auto* expected =
         R"(RWByteAddressBuffer data : register(u0, space1);
 
-void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
-  buffer.Store3((offset + 0u), asuint(value[0u]));
-  buffer.Store3((offset + 16u), asuint(value[1u]));
+void data_store(uint offset, float2x3 value) {
+  data.Store3((offset + 0u), asuint(value[0u]));
+  data.Store3((offset + 16u), asuint(value[1u]));
 }
 
 void main() {
-  tint_symbol(data, 16u, float2x3((0.0f).xxx, (0.0f).xxx));
+  data_store(16u, float2x3((0.0f).xxx, (0.0f).xxx));
   return;
 }
 )";
@@ -1388,13 +1390,13 @@
 
 RWByteAddressBuffer data : register(u0, space1);
 
-Inner tint_symbol(RWByteAddressBuffer buffer, uint offset) {
-  const Inner tint_symbol_2 = {asint(buffer.Load((offset + 0u)))};
-  return tint_symbol_2;
+Inner data_load(uint offset) {
+  const Inner tint_symbol = {asint(data.Load((offset + 0u)))};
+  return tint_symbol;
 }
 
 void main() {
-  Inner x = tint_symbol(data, 48u);
+  Inner x = data_load(48u);
   return;
 }
 )";
@@ -1440,14 +1442,14 @@
   uint4 data[6];
 };
 
-Inner tint_symbol(uint4 buffer[6], uint offset) {
+Inner data_load(uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  const Inner tint_symbol_2 = {asint(buffer[scalar_offset / 4][scalar_offset % 4])};
-  return tint_symbol_2;
+  const Inner tint_symbol = {asint(data[scalar_offset / 4][scalar_offset % 4])};
+  return tint_symbol;
 }
 
 void main() {
-  Inner x = tint_symbol(data, 48u);
+  Inner x = data_load(48u);
   return;
 }
 )";
diff --git a/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc b/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
index 961a27b..e349b5c 100644
--- a/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
@@ -26,7 +26,7 @@
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
@@ -60,7 +60,7 @@
                                          Member(0, "z", ty.f32()),
                                          Member(4, "a", ty.array<f32>()),
                                      });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
@@ -92,7 +92,7 @@
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength_ViaLets) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     auto* p = Let("p", AddressOf("b"));
@@ -129,9 +129,9 @@
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
-    GlobalVar("c", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(2_a),
+    GlobalVar("c", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(2_a),
               Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
@@ -159,10 +159,10 @@
 ByteAddressBuffer c : register(t2, space2);
 
 void a_func() {
-  uint tint_symbol_4 = 0u;
-  b.GetDimensions(tint_symbol_4);
-  const uint tint_symbol_5 = ((tint_symbol_4 - 0u) / 4u);
-  uint len = (tint_symbol_5 + ((tint_symbol_1[1].w - 0u) / 4u));
+  uint tint_symbol_3 = 0u;
+  b.GetDimensions(tint_symbol_3);
+  const uint tint_symbol_4 = ((tint_symbol_3 - 0u) / 4u);
+  uint len = (tint_symbol_4 + ((tint_symbol_1[1].w - 0u) / 4u));
   return;
 }
 )";
@@ -242,7 +242,7 @@
     // let p : ptr<function, i32> = &v;
     // let x : i32 = *p;
     auto* v = Var("v", ty.i32());
-    auto* p = Let("p", ty.pointer<i32>(type::AddressSpace::kFunction), AddressOf(v));
+    auto* p = Let("p", ty.pointer<i32>(builtin::AddressSpace::kFunction), AddressOf(v));
     auto* x = Var("x", ty.i32(), Deref(p));
 
     Func("main", utils::Empty, ty.void_(),
@@ -276,11 +276,12 @@
     // let vp : ptr<function, vec4<f32>> = &(*mp)[2i];
     // let v : vec4<f32> = *vp;
     auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4_u));
-    auto* ap = Let("ap", ty.pointer(ty.array(ty.mat4x4<f32>(), 4_u), type::AddressSpace::kFunction),
-                   AddressOf(a));
-    auto* mp = Let("mp", ty.pointer(ty.mat4x4<f32>(), type::AddressSpace::kFunction),
+    auto* ap =
+        Let("ap", ty.pointer(ty.array(ty.mat4x4<f32>(), 4_u), builtin::AddressSpace::kFunction),
+            AddressOf(a));
+    auto* mp = Let("mp", ty.pointer(ty.mat4x4<f32>(), builtin::AddressSpace::kFunction),
                    AddressOf(IndexAccessor(Deref(ap), 3_i)));
-    auto* vp = Let("vp", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kFunction),
+    auto* vp = Let("vp", ty.pointer(ty.vec4<f32>(), builtin::AddressSpace::kFunction),
                    AddressOf(IndexAccessor(Deref(mp), 2_i)));
     auto* v = Var("v", ty.vec4<f32>(), Deref(vp));
 
diff --git a/src/tint/writer/hlsl/generator_impl_switch_test.cc b/src/tint/writer/hlsl/generator_impl_switch_test.cc
index 6426b7c..810a99b 100644
--- a/src/tint/writer/hlsl/generator_impl_switch_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_switch_test.cc
@@ -22,7 +22,7 @@
 using HlslGeneratorImplTest_Switch = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Switch, Emit_Switch) {
-    GlobalVar("cond", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* s = Switch(                             //
         Expr("cond"),                             //
         Case(CaseSelector(5_i), Block(Break())),  //
@@ -46,7 +46,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Switch, Emit_Switch_MixedDefault) {
-    GlobalVar("cond", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* s = Switch(  //
         Expr("cond"),  //
         Case(utils::Vector{CaseSelector(5_i), DefaultCaseSelector()}, Block(Break())));
@@ -76,8 +76,8 @@
     //     }
     //   }
     // }
-    GlobalVar("cond", ty.i32(), type::AddressSpace::kPrivate);
-    GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.i32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* s = Switch(  //
         Expr("cond"),  //
         DefaultCase(Block(Assign(Expr("a"), Expr(42_i)))));
@@ -109,13 +109,13 @@
     //     }
     //   }
     // }
-    GlobalVar("global", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("global", ty.i32(), builtin::AddressSpace::kPrivate);
     Func("bar", {}, ty.i32(),
          utils::Vector{                               //
                        Assign("global", Expr(84_i)),  //
                        Return("global")});
 
-    GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* s = Switch(  //
         Call("bar"),   //
         DefaultCase(Block(Assign(Expr("a"), Expr(42_i)))));
diff --git a/src/tint/writer/hlsl/generator_impl_type_test.cc b/src/tint/writer/hlsl/generator_impl_type_test.cc
index be5a900..71fe338 100644
--- a/src/tint/writer/hlsl/generator_impl_type_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_type_test.cc
@@ -34,52 +34,52 @@
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Array) {
     auto arr = ty.array<bool, 4>();
-    ast::Type ty = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, "ary"))
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, "ary"))
         << gen.error();
     EXPECT_EQ(out.str(), "bool ary[4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
     auto arr = ty.array(ty.array<bool, 4>(), 5_u);
-    ast::Type ty = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, "ary"))
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, "ary"))
         << gen.error();
     EXPECT_EQ(out.str(), "bool ary[5][4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
     auto arr = ty.array(ty.array(ty.array<bool, 4>(), 5_u), 6_u);
-    ast::Type ty = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, "ary"))
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, "ary"))
         << gen.error();
     EXPECT_EQ(out.str(), "bool ary[6][5][4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Array_WithoutName) {
     auto arr = ty.array<bool, 4>();
-    ast::Type ty = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), type::AddressSpace::kNone,
-                             type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "bool[4]");
 }
@@ -90,7 +90,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, bool_, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, bool_, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "bool");
 }
@@ -101,7 +102,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, f16, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, f16, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "float16_t");
 }
@@ -112,7 +114,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, f32, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, f32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "float");
 }
@@ -123,7 +126,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, i32, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, i32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "int");
 }
@@ -136,7 +140,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, mat2x3, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "matrix<float16_t, 2, 3>");
 }
@@ -149,7 +154,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, mat2x3, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "float2x3");
 }
@@ -159,7 +165,7 @@
                                  Member("a", ty.i32()),
                                  Member("b", ty.f32()),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
@@ -178,8 +184,8 @@
                                  Member("a", ty.i32()),
                                  Member("b", ty.f32()),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Binding(0_a),
-              Group(0_a));
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Binding(0_a), Group(0_a));
 
     GeneratorImpl& gen = Build();
 
@@ -192,13 +198,14 @@
                                  Member("a", ty.i32()),
                                  Member("b", ty.f32()),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
     auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, sem_s, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, sem_s, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "S");
 }
@@ -208,7 +215,7 @@
                                  Member("double", ty.i32()),
                                  Member("float", ty.f32()),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -225,7 +232,7 @@
                                  Member("a", ty.i32(), utils::Vector{MemberOffset(0_a)}),
                                  Member("b", ty.f32(), utils::Vector{MemberOffset(8_a)}),
                              });
-    GlobalVar("g", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("g", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
@@ -245,7 +252,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, u32, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, u32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "uint");
 }
@@ -257,7 +265,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, vec3, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, vec3, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "float3");
 }
@@ -268,7 +277,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, void_, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, void_, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "void");
 }
@@ -279,7 +289,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, sampler, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "SamplerState");
 }
@@ -290,7 +301,8 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, sampler, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
+                             builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "SamplerComparisonState");
 }
@@ -313,7 +325,7 @@
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Decl(Var("v", Call("textureDimensions", "tex"))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -344,7 +356,7 @@
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Decl(Var("v", Call("textureDimensions", "tex"))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -388,7 +400,7 @@
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Decl(Var("v", Call("textureDimensions", "tex"))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -500,14 +512,15 @@
     GeneratorImpl& gen = Build();
 
     std::stringstream out;
-    ASSERT_TRUE(gen.EmitType(out, s, type::AddressSpace::kNone, type::Access::kReadWrite, ""))
+    ASSERT_TRUE(
+        gen.EmitType(out, s, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
     EXPECT_EQ(out.str(), "Texture2DMS<float4>");
 }
 
 struct HlslStorageTextureData {
     type::TextureDimension dim;
-    type::TexelFormat imgfmt;
+    builtin::TexelFormat imgfmt;
     std::string result;
 };
 inline std::ostream& operator<<(std::ostream& out, HlslStorageTextureData data) {
@@ -518,7 +531,7 @@
 TEST_P(HlslStorageTexturesTest, Emit) {
     auto params = GetParam();
 
-    auto t = ty.storage_texture(params.dim, params.imgfmt, type::Access::kWrite);
+    auto t = ty.storage_texture(params.dim, params.imgfmt, builtin::Access::kWrite);
 
     GlobalVar("tex", t,
               utils::Vector{
@@ -528,7 +541,7 @@
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("textureDimensions", "tex")),
+             Decl(Var("v", Call("textureDimensions", "tex"))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -543,31 +556,31 @@
     HlslGeneratorImplTest_Type,
     HlslStorageTexturesTest,
     testing::Values(
-        HlslStorageTextureData{type::TextureDimension::k1d, type::TexelFormat::kRgba8Unorm,
+        HlslStorageTextureData{type::TextureDimension::k1d, builtin::TexelFormat::kRgba8Unorm,
                                "RWTexture1D<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k2d, type::TexelFormat::kRgba16Float,
+        HlslStorageTextureData{type::TextureDimension::k2d, builtin::TexelFormat::kRgba16Float,
                                "RWTexture2D<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k2dArray, type::TexelFormat::kR32Float,
+        HlslStorageTextureData{type::TextureDimension::k2dArray, builtin::TexelFormat::kR32Float,
                                "RWTexture2DArray<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k3d, type::TexelFormat::kRg32Float,
+        HlslStorageTextureData{type::TextureDimension::k3d, builtin::TexelFormat::kRg32Float,
                                "RWTexture3D<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k1d, type::TexelFormat::kRgba32Float,
+        HlslStorageTextureData{type::TextureDimension::k1d, builtin::TexelFormat::kRgba32Float,
                                "RWTexture1D<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k2d, type::TexelFormat::kRgba16Uint,
+        HlslStorageTextureData{type::TextureDimension::k2d, builtin::TexelFormat::kRgba16Uint,
                                "RWTexture2D<uint4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k2dArray, type::TexelFormat::kR32Uint,
+        HlslStorageTextureData{type::TextureDimension::k2dArray, builtin::TexelFormat::kR32Uint,
                                "RWTexture2DArray<uint4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k3d, type::TexelFormat::kRg32Uint,
+        HlslStorageTextureData{type::TextureDimension::k3d, builtin::TexelFormat::kRg32Uint,
                                "RWTexture3D<uint4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k1d, type::TexelFormat::kRgba32Uint,
+        HlslStorageTextureData{type::TextureDimension::k1d, builtin::TexelFormat::kRgba32Uint,
                                "RWTexture1D<uint4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k2d, type::TexelFormat::kRgba16Sint,
+        HlslStorageTextureData{type::TextureDimension::k2d, builtin::TexelFormat::kRgba16Sint,
                                "RWTexture2D<int4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k2dArray, type::TexelFormat::kR32Sint,
+        HlslStorageTextureData{type::TextureDimension::k2dArray, builtin::TexelFormat::kR32Sint,
                                "RWTexture2DArray<int4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k3d, type::TexelFormat::kRg32Sint,
+        HlslStorageTextureData{type::TextureDimension::k3d, builtin::TexelFormat::kRg32Sint,
                                "RWTexture3D<int4> tex : register(u1, space2);"},
-        HlslStorageTextureData{type::TextureDimension::k1d, type::TexelFormat::kRgba32Sint,
+        HlslStorageTextureData{type::TextureDimension::k1d, builtin::TexelFormat::kRgba32Sint,
                                "RWTexture1D<int4> tex : register(u1, space2);"}));
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_unary_op_test.cc b/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
index 93a61dc..4bf4329 100644
--- a/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
@@ -20,7 +20,7 @@
 using HlslUnaryOpTest = TestHelper;
 
 TEST_F(HlslUnaryOpTest, AddressOf) {
-    GlobalVar("expr", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
     WrapInFunction(op);
 
@@ -32,7 +32,7 @@
 }
 
 TEST_F(HlslUnaryOpTest, Complement) {
-    GlobalVar("expr", ty.u32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.u32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
     WrapInFunction(op);
 
@@ -44,7 +44,7 @@
 }
 
 TEST_F(HlslUnaryOpTest, Indirection) {
-    GlobalVar("G", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("G", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* p = Let("expr", create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
     WrapInFunction(p, op);
@@ -57,7 +57,7 @@
 }
 
 TEST_F(HlslUnaryOpTest, Not) {
-    GlobalVar("expr", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.bool_(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
     WrapInFunction(op);
 
@@ -69,7 +69,7 @@
 }
 
 TEST_F(HlslUnaryOpTest, Negation) {
-    GlobalVar("expr", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
     WrapInFunction(op);
 
diff --git a/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
index fedf476..f8420ae 100644
--- a/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
@@ -357,7 +357,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
 
     WrapInFunction(Expr("a"));
 
diff --git a/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc b/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
index ea30962..3895aba 100644
--- a/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
@@ -27,7 +27,7 @@
 using HlslGeneratorImplTest_WorkgroupVar = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_WorkgroupVar, Basic) {
-    GlobalVar("wg", ty.f32(), type::AddressSpace::kWorkgroup);
+    GlobalVar("wg", ty.f32(), builtin::AddressSpace::kWorkgroup);
 
     Func("main", utils::Empty, ty.void_(), utils::Vector{Assign("wg", 1.2_f)},
          utils::Vector{
@@ -43,7 +43,7 @@
 TEST_F(HlslGeneratorImplTest_WorkgroupVar, Aliased) {
     auto* alias = Alias("F32", ty.f32());
 
-    GlobalVar("wg", ty.Of(alias), type::AddressSpace::kWorkgroup);
+    GlobalVar("wg", ty.Of(alias), builtin::AddressSpace::kWorkgroup);
 
     Func("main", utils::Empty, ty.void_(), utils::Vector{Assign("wg", 1.2_f)},
          utils::Vector{
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 87928b4..c433207 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -37,8 +37,8 @@
 #include "src/tint/sem/module.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/switch_statement.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/transform/array_length_from_uniform.h"
 #include "src/tint/transform/builtin_polyfill.h"
@@ -204,7 +204,7 @@
         // Use the SSBO binding numbers as the indices for the buffer size lookups.
         for (auto* var : in->AST().GlobalVariables()) {
             auto* global = in->Sem().Get<sem::GlobalVariable>(var);
-            if (global && global->AddressSpace() == type::AddressSpace::kStorage) {
+            if (global && global->AddressSpace() == builtin::AddressSpace::kStorage) {
                 array_length_from_uniform_cfg.bindpoint_to_size_index.emplace(
                     global->BindingPoint(), global->BindingPoint().binding);
             }
@@ -640,8 +640,8 @@
     return Switch(
         target, [&](const sem::Function* func) { return EmitFunctionCall(out, call, func); },
         [&](const sem::Builtin* builtin) { return EmitBuiltinCall(out, call, builtin); },
-        [&](const sem::TypeConversion* conv) { return EmitTypeConversion(out, call, conv); },
-        [&](const sem::TypeInitializer* ctor) { return EmitTypeInitializer(out, call, ctor); },
+        [&](const sem::ValueConversion* conv) { return EmitTypeConversion(out, call, conv); },
+        [&](const sem::ValueConstructor* ctor) { return EmitTypeInitializer(out, call, ctor); },
         [&](Default) {
             TINT_ICE(Writer, diagnostics_) << "unhandled call target: " << target->TypeInfo().name;
             return false;
@@ -785,7 +785,7 @@
 
 bool GeneratorImpl::EmitTypeConversion(std::ostream& out,
                                        const sem::Call* call,
-                                       const sem::TypeConversion* conv) {
+                                       const sem::ValueConversion* conv) {
     if (!EmitType(out, conv->Target(), "")) {
         return false;
     }
@@ -801,7 +801,7 @@
 
 bool GeneratorImpl::EmitTypeInitializer(std::ostream& out,
                                         const sem::Call* call,
-                                        const sem::TypeInitializer* ctor) {
+                                        const sem::ValueConstructor* ctor) {
     auto* type = ctor->ReturnType();
 
     const char* terminator = ")";
@@ -1939,33 +1939,34 @@
     return "";
 }
 
-std::string GeneratorImpl::interpolation_to_attribute(ast::InterpolationType type,
-                                                      ast::InterpolationSampling sampling) const {
+std::string GeneratorImpl::interpolation_to_attribute(
+    builtin::InterpolationType type,
+    builtin::InterpolationSampling sampling) const {
     std::string attr;
     switch (sampling) {
-        case ast::InterpolationSampling::kCenter:
+        case builtin::InterpolationSampling::kCenter:
             attr = "center_";
             break;
-        case ast::InterpolationSampling::kCentroid:
+        case builtin::InterpolationSampling::kCentroid:
             attr = "centroid_";
             break;
-        case ast::InterpolationSampling::kSample:
+        case builtin::InterpolationSampling::kSample:
             attr = "sample_";
             break;
-        case ast::InterpolationSampling::kUndefined:
+        case builtin::InterpolationSampling::kUndefined:
             break;
     }
     switch (type) {
-        case ast::InterpolationType::kPerspective:
+        case builtin::InterpolationType::kPerspective:
             attr += "perspective";
             break;
-        case ast::InterpolationType::kLinear:
+        case builtin::InterpolationType::kLinear:
             attr += "no_perspective";
             break;
-        case ast::InterpolationType::kFlat:
+        case builtin::InterpolationType::kFlat:
             attr += "flat";
             break;
-        case ast::InterpolationType::kUndefined:
+        case builtin::InterpolationType::kUndefined:
             break;
     }
     return attr;
@@ -2048,15 +2049,15 @@
                 },
                 [&](const type::Pointer* ptr) {
                     switch (ptr->AddressSpace()) {
-                        case type::AddressSpace::kWorkgroup: {
+                        case builtin::AddressSpace::kWorkgroup: {
                             auto& allocations = workgroup_allocations_[func_name];
                             out << " [[threadgroup(" << allocations.size() << ")]]";
                             allocations.push_back(ptr->StoreType()->Size());
                             return true;
                         }
 
-                        case type::AddressSpace::kStorage:
-                        case type::AddressSpace::kUniform: {
+                        case builtin::AddressSpace::kStorage:
+                        case builtin::AddressSpace::kUniform: {
                             uint32_t binding = get_binding_index(param);
                             if (binding == kInvalidBindingIndex) {
                                 return false;
@@ -2076,14 +2077,15 @@
                     auto& attrs = param->attributes;
                     bool builtin_found = false;
                     for (auto* attr : attrs) {
-                        auto* builtin = attr->As<ast::BuiltinAttribute>();
-                        if (!builtin) {
+                        auto* builtin_attr = attr->As<ast::BuiltinAttribute>();
+                        if (!builtin_attr) {
                             continue;
                         }
+                        auto builtin = program_->Sem().Get(builtin_attr)->Value();
 
                         builtin_found = true;
 
-                        auto name = builtin_to_attribute(builtin->builtin);
+                        auto name = builtin_to_attribute(builtin);
                         if (name.empty()) {
                             diagnostics_.add_error(diag::System::Writer, "unknown builtin");
                             return false;
@@ -2610,7 +2612,7 @@
             return true;
         },
         [&](const type::Pointer* ptr) {
-            if (ptr->Access() == type::Access::kRead) {
+            if (ptr->Access() == builtin::Access::kRead) {
                 out << "const ";
             }
             if (!EmitAddressSpace(out, ptr->AddressSpace())) {
@@ -2694,9 +2696,9 @@
                     }
 
                     std::string access_str;
-                    if (storage->access() == type::Access::kRead) {
+                    if (storage->access() == builtin::Access::kRead) {
                         out << ", access::read";
-                    } else if (storage->access() == type::Access::kWrite) {
+                    } else if (storage->access() == builtin::Access::kWrite) {
                         out << ", access::write";
                     } else {
                         diagnostics_.add_error(diag::System::Writer,
@@ -2760,20 +2762,20 @@
     return true;
 }
 
-bool GeneratorImpl::EmitAddressSpace(std::ostream& out, type::AddressSpace sc) {
+bool GeneratorImpl::EmitAddressSpace(std::ostream& out, builtin::AddressSpace sc) {
     switch (sc) {
-        case type::AddressSpace::kFunction:
-        case type::AddressSpace::kPrivate:
-        case type::AddressSpace::kHandle:
+        case builtin::AddressSpace::kFunction:
+        case builtin::AddressSpace::kPrivate:
+        case builtin::AddressSpace::kHandle:
             out << "thread";
             return true;
-        case type::AddressSpace::kWorkgroup:
+        case builtin::AddressSpace::kWorkgroup:
             out << "threadgroup";
             return true;
-        case type::AddressSpace::kStorage:
+        case builtin::AddressSpace::kStorage:
             out << "device";
             return true;
-        case type::AddressSpace::kUniform:
+        case builtin::AddressSpace::kUniform:
             out << "constant";
             return true;
         default:
@@ -2853,8 +2855,9 @@
             for (auto* attr : decl->attributes) {
                 bool ok = Switch(
                     attr,
-                    [&](const ast::BuiltinAttribute* builtin) {
-                        auto name = builtin_to_attribute(builtin->builtin);
+                    [&](const ast::BuiltinAttribute* builtin_attr) {
+                        auto builtin = program_->Sem().Get(builtin_attr)->Value();
+                        auto name = builtin_to_attribute(builtin);
                         if (name.empty()) {
                             diagnostics_.add_error(diag::System::Writer, "unknown builtin");
                             return false;
@@ -2888,8 +2891,21 @@
                         return true;
                     },
                     [&](const ast::InterpolateAttribute* interpolate) {
-                        auto name =
-                            interpolation_to_attribute(interpolate->type, interpolate->sampling);
+                        auto& sem = program_->Sem();
+                        auto i_type =
+                            sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(
+                                   interpolate->type)
+                                ->Value();
+
+                        auto i_smpl = builtin::InterpolationSampling::kUndefined;
+                        if (interpolate->sampling) {
+                            i_smpl =
+                                sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
+                                       interpolate->sampling)
+                                    ->Value();
+                        }
+
+                        auto name = interpolation_to_attribute(i_type, i_smpl);
                         if (name.empty()) {
                             diagnostics_.add_error(diag::System::Writer,
                                                    "unknown interpolation attribute");
@@ -3025,14 +3041,13 @@
     auto out = line();
 
     switch (sem->AddressSpace()) {
-        case type::AddressSpace::kFunction:
-        case type::AddressSpace::kHandle:
-        case type::AddressSpace::kNone:
+        case builtin::AddressSpace::kFunction:
+        case builtin::AddressSpace::kHandle:
             break;
-        case type::AddressSpace::kPrivate:
+        case builtin::AddressSpace::kPrivate:
             out << "thread ";
             break;
-        case type::AddressSpace::kWorkgroup:
+        case builtin::AddressSpace::kWorkgroup:
             out << "threadgroup ";
             break;
         default:
@@ -3054,9 +3069,9 @@
         if (!EmitExpression(out, var->initializer)) {
             return false;
         }
-    } else if (sem->AddressSpace() == type::AddressSpace::kPrivate ||
-               sem->AddressSpace() == type::AddressSpace::kFunction ||
-               sem->AddressSpace() == type::AddressSpace::kNone) {
+    } else if (sem->AddressSpace() == builtin::AddressSpace::kPrivate ||
+               sem->AddressSpace() == builtin::AddressSpace::kFunction ||
+               sem->AddressSpace() == builtin::AddressSpace::kUndefined) {
         out << " = ";
         if (!EmitZeroValue(out, type)) {
             return false;
@@ -3074,14 +3089,14 @@
     auto out = line();
 
     switch (sem->AddressSpace()) {
-        case type::AddressSpace::kFunction:
-        case type::AddressSpace::kHandle:
-        case type::AddressSpace::kNone:
+        case builtin::AddressSpace::kFunction:
+        case builtin::AddressSpace::kHandle:
+        case builtin::AddressSpace::kUndefined:
             break;
-        case type::AddressSpace::kPrivate:
+        case builtin::AddressSpace::kPrivate:
             out << "thread ";
             break;
-        case type::AddressSpace::kWorkgroup:
+        case builtin::AddressSpace::kWorkgroup:
             out << "threadgroup ";
             break;
         default:
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index 750bed5..9c7c0d4 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -36,6 +36,7 @@
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/switch_statement.h"
 #include "src/tint/ast/unary_op_expression.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program.h"
 #include "src/tint/scope_stack.h"
 #include "src/tint/sem/struct.h"
@@ -45,10 +46,10 @@
 
 // Forward declarations
 namespace tint::sem {
-class Call;
 class Builtin;
-class TypeInitializer;
-class TypeConversion;
+class Call;
+class ValueConstructor;
+class ValueConversion;
 }  // namespace tint::sem
 
 namespace tint::writer::msl {
@@ -143,22 +144,22 @@
     /// @param builtin the builtin being called
     /// @returns true if the call expression is emitted
     bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
-    /// Handles generating a type conversion expression
+    /// Handles generating a value conversion expression
     /// @param out the output of the expression stream
     /// @param call the call expression
-    /// @param conv the type conversion
+    /// @param conv the value conversion
     /// @returns true if the expression is emitted
     bool EmitTypeConversion(std::ostream& out,
                             const sem::Call* call,
-                            const sem::TypeConversion* conv);
-    /// Handles generating a type initializer
+                            const sem::ValueConversion* conv);
+    /// Handles generating a value constructor
     /// @param out the output of the expression stream
     /// @param call the call expression
-    /// @param ctor the type initializer
+    /// @param ctor the value constructor
     /// @returns true if the initializer is emitted
     bool EmitTypeInitializer(std::ostream& out,
                              const sem::Call* call,
-                             const sem::TypeInitializer* ctor);
+                             const sem::ValueConstructor* ctor);
     /// Handles generating a function call
     /// @param out the output of the expression stream
     /// @param call the call expression
@@ -326,7 +327,7 @@
     /// @param out the output of the type stream
     /// @param sc the address space to generate
     /// @returns true if the address space is emitted
-    bool EmitAddressSpace(std::ostream& out, type::AddressSpace sc);
+    bool EmitAddressSpace(std::ostream& out, builtin::AddressSpace sc);
     /// Handles generating a struct declaration. If the structure has already been emitted, then
     /// this function will simply return `true` without emitting anything.
     /// @param buffer the text buffer that the type declaration will be written to
@@ -366,8 +367,8 @@
     /// @param type the interpolation type
     /// @param sampling the interpolation sampling
     /// @returns the string name of the attribute or blank on error
-    std::string interpolation_to_attribute(ast::InterpolationType type,
-                                           ast::InterpolationSampling sampling) const;
+    std::string interpolation_to_attribute(builtin::InterpolationType type,
+                                           builtin::InterpolationSampling sampling) const;
 
   private:
     // A pair of byte size and alignment `uint32_t`s.
@@ -410,7 +411,7 @@
     /// Name of atomicCompareExchangeWeak() helper for the given pointer storage
     /// class and struct return type
     using ACEWKeyType =
-        utils::UnorderedKeyWrapper<std::tuple<type::AddressSpace, const sem::Struct*>>;
+        utils::UnorderedKeyWrapper<std::tuple<builtin::AddressSpace, const sem::Struct*>>;
     std::unordered_map<ACEWKeyType, std::string> atomicCompareExchangeWeak_;
 
     /// Unique name of the 'TINT_INVARIANT' preprocessor define.
diff --git a/src/tint/writer/msl/generator_impl_array_accessor_test.cc b/src/tint/writer/msl/generator_impl_array_accessor_test.cc
index eae2c17..47145d1 100644
--- a/src/tint/writer/msl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/msl/generator_impl_array_accessor_test.cc
@@ -34,7 +34,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, IndexAccessor_OfDref) {
-    GlobalVar("ary", ty.array<i32, 10>(), type::AddressSpace::kPrivate);
+    GlobalVar("ary", ty.array<i32, 10>(), builtin::AddressSpace::kPrivate);
 
     auto* p = Let("p", AddressOf("ary"));
     auto* expr = IndexAccessor(Deref("p"), 5_i);
diff --git a/src/tint/writer/msl/generator_impl_builtin_test.cc b/src/tint/writer/msl/generator_impl_builtin_test.cc
index 0eabc02..84fb7d5 100644
--- a/src/tint/writer/msl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_test.cc
@@ -216,21 +216,21 @@
     if (param.type == CallParamType::kF16) {
         Enable(builtin::Extension::kF16);
 
-        GlobalVar("h2", ty.vec2<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("h3", ty.vec3<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("hm2x2", ty.mat2x2<f16>(), type::AddressSpace::kPrivate);
-        GlobalVar("hm3x2", ty.mat3x2<f16>(), type::AddressSpace::kPrivate);
+        GlobalVar("h2", ty.vec2<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("h3", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("hm2x2", ty.mat2x2<f16>(), builtin::AddressSpace::kPrivate);
+        GlobalVar("hm3x2", ty.mat3x2<f16>(), builtin::AddressSpace::kPrivate);
     }
 
-    GlobalVar("f2", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("f3", ty.vec3<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("f4", ty.vec4<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("u1", ty.u32(), type::AddressSpace::kPrivate);
-    GlobalVar("u2", ty.vec2<u32>(), type::AddressSpace::kPrivate);
-    GlobalVar("i2", ty.vec2<i32>(), type::AddressSpace::kPrivate);
-    GlobalVar("b2", ty.vec2<bool>(), type::AddressSpace::kPrivate);
-    GlobalVar("m2x2", ty.mat2x2<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("m3x2", ty.mat3x2<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("f2", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("f3", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("f4", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("u1", ty.u32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("u2", ty.vec2<u32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("i2", ty.vec2<i32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b2", ty.vec2<bool>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("m2x2", ty.mat2x2<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("m3x2", ty.mat3x2<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* call = GenerateCall(param.builtin, param.type, this);
     ASSERT_NE(nullptr, call) << "Unhandled builtin";
@@ -370,11 +370,11 @@
                     "unpack_unorm2x16_to_float"}));
 
 TEST_F(MslGeneratorImplTest, Builtin_Call) {
-    GlobalVar("param1", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.vec2<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("dot", "param1", "param2");
-    WrapInFunction(CallStmt(call));
+    WrapInFunction(Decl(Var("r", call)));
 
     GeneratorImpl& gen = Build();
 
@@ -1047,8 +1047,8 @@
 
 TEST_F(MslGeneratorImplTest, Pack2x16Float) {
     auto* call = Call("pack2x16float", "p1");
-    GlobalVar("p1", ty.vec2<f32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.vec2<f32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
 
     GeneratorImpl& gen = Build();
 
@@ -1059,8 +1059,8 @@
 
 TEST_F(MslGeneratorImplTest, Unpack2x16Float) {
     auto* call = Call("unpack2x16float", "p1");
-    GlobalVar("p1", ty.u32(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(call));
+    GlobalVar("p1", ty.u32(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", call)));
 
     GeneratorImpl& gen = Build();
 
@@ -1070,8 +1070,8 @@
 }
 
 TEST_F(MslGeneratorImplTest, DotI32) {
-    GlobalVar("v", ty.vec3<i32>(), type::AddressSpace::kPrivate);
-    WrapInFunction(CallStmt(Call("dot", "v", "v")));
+    GlobalVar("v", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
+    WrapInFunction(Decl(Var("r", Call("dot", "v", "v"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -1086,7 +1086,7 @@
 }
 kernel void test_function() {
   thread int3 tint_symbol = 0;
-  tint_dot3(tint_symbol, tint_symbol);
+  int r = tint_dot3(tint_symbol, tint_symbol);
   return;
 }
 
diff --git a/src/tint/writer/msl/generator_impl_builtin_texture_test.cc b/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
index 16688ef..f3d65b1 100644
--- a/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
@@ -277,7 +277,8 @@
     param.BuildSamplerVariable(this);
 
     auto* call = Call(param.function, param.args(this));
-    auto* stmt = CallStmt(call);
+    auto* stmt = param.returns_value ? static_cast<const ast::Statement*>(Assign(Phony(), call))
+                                     : static_cast<const ast::Statement*>(CallStmt(call));
 
     Func("main", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
diff --git a/src/tint/writer/msl/generator_impl_call_test.cc b/src/tint/writer/msl/generator_impl_call_test.cc
index 4449c2b..26da4e4 100644
--- a/src/tint/writer/msl/generator_impl_call_test.cc
+++ b/src/tint/writer/msl/generator_impl_call_test.cc
@@ -45,8 +45,8 @@
          utils::Vector{
              Return(1.23_f),
          });
-    GlobalVar("param1", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("my_func", "param1", "param2");
     WrapInFunction(call);
@@ -65,8 +65,8 @@
              Param(Sym(), ty.f32()),
          },
          ty.void_(), utils::Empty, utils::Empty);
-    GlobalVar("param1", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("my_func", "param1", "param2");
     auto* stmt = CallStmt(call);
diff --git a/src/tint/writer/msl/generator_impl_initializer_test.cc b/src/tint/writer/msl/generator_impl_constructor_test.cc
similarity index 82%
rename from src/tint/writer/msl/generator_impl_initializer_test.cc
rename to src/tint/writer/msl/generator_impl_constructor_test.cc
index fbd1def..ba567ab 100644
--- a/src/tint/writer/msl/generator_impl_initializer_test.cc
+++ b/src/tint/writer/msl/generator_impl_constructor_test.cc
@@ -22,9 +22,9 @@
 
 using ::testing::HasSubstr;
 
-using MslGeneratorImplTest = TestHelper;
+using MslGeneratorImplTest_Constructor = TestHelper;
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Bool) {
+TEST_F(MslGeneratorImplTest_Constructor, Bool) {
     WrapInFunction(Expr(false));
 
     GeneratorImpl& gen = Build();
@@ -33,7 +33,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Int) {
+TEST_F(MslGeneratorImplTest_Constructor, Int) {
     WrapInFunction(Expr(-12345_i));
 
     GeneratorImpl& gen = Build();
@@ -42,7 +42,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_UInt) {
+TEST_F(MslGeneratorImplTest_Constructor, UInt) {
     WrapInFunction(Expr(56779_u));
 
     GeneratorImpl& gen = Build();
@@ -51,7 +51,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Float) {
+TEST_F(MslGeneratorImplTest_Constructor, Float) {
     // Use a number close to 1<<30 but whose decimal representation ends in 0.
     WrapInFunction(Expr(f32((1 << 30) - 4)));
 
@@ -61,7 +61,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_F16) {
+TEST_F(MslGeneratorImplTest_Constructor, F16) {
     Enable(builtin::Extension::kF16);
 
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
@@ -73,7 +73,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("32752.0h"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Float) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Float) {
     WrapInFunction(Call<f32>(-1.2e-5_f));
 
     GeneratorImpl& gen = Build();
@@ -82,7 +82,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-0.000012f"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_F16) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(Call<f16>(-1.2e-3_h));
@@ -93,7 +93,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-0.00119972229h"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Bool) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Bool) {
     WrapInFunction(Call<bool>(true));
 
     GeneratorImpl& gen = Build();
@@ -102,7 +102,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("true"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Int) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Int) {
     WrapInFunction(Call<i32>(-12345_i));
 
     GeneratorImpl& gen = Build();
@@ -111,7 +111,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Uint) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Uint) {
     WrapInFunction(Call<u32>(12345_u));
 
     GeneratorImpl& gen = Build();
@@ -120,7 +120,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("12345u"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_F32) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_F32) {
     WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
 
     GeneratorImpl& gen = Build();
@@ -129,7 +129,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_F16) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
@@ -140,7 +140,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("half3(1.0h, 2.0h, 3.0h)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_Empty_F32) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_Empty_F32) {
     WrapInFunction(vec3<f32>());
 
     GeneratorImpl& gen = Build();
@@ -149,7 +149,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float3(0.0f)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_Empty_F16) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>());
@@ -160,7 +160,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("half3(0.0h)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_F32_Literal) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Literal) {
     WrapInFunction(vec3<f32>(2_f));
 
     GeneratorImpl& gen = Build();
@@ -169,7 +169,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float3(2.0f)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_F16_Literal) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Literal) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(2_h));
@@ -180,7 +180,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("half3(2.0h)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_F32_Var) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Var) {
     auto* var = Var("v", Expr(2_f));
     auto* cast = vec3<f32>(var);
     WrapInFunction(var, cast);
@@ -192,7 +192,7 @@
   float3 const tint_symbol = float3(v);)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_F16_Var) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Var) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
@@ -206,7 +206,7 @@
   half3 const tint_symbol = half3(v);)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_Bool) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Bool) {
     WrapInFunction(vec3<bool>(true));
 
     GeneratorImpl& gen = Build();
@@ -215,7 +215,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("bool3(true)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_Int) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Int) {
     WrapInFunction(vec3<i32>(2_i));
 
     GeneratorImpl& gen = Build();
@@ -224,7 +224,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("int3(2)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_UInt) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_UInt) {
     WrapInFunction(vec3<u32>(2_u));
 
     GeneratorImpl& gen = Build();
@@ -233,7 +233,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("uint3(2u)"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_F32) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_F32) {
     WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
 
     GeneratorImpl& gen = Build();
@@ -244,7 +244,7 @@
                 HasSubstr("float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_F16) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
@@ -257,7 +257,7 @@
                 HasSubstr("half2x3(half3(1.0h, 2.0h, 3.0h), half3(3.0h, 4.0h, 5.0h))"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_Complex_F32) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_Complex_F32) {
     // mat4x4<f32>(
     //     vec4<f32>(2.0f, 3.0f, 4.0f, 8.0f),
     //     vec4<f32>(),
@@ -271,10 +271,10 @@
     auto* vector_identical_init =
         vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
 
-    auto* initializer = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
+    auto* constructor = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
                                     vector_identical_init);
 
-    WrapInFunction(initializer);
+    WrapInFunction(constructor);
 
     GeneratorImpl& gen = Build();
 
@@ -284,7 +284,7 @@
                                         "float4(7.0f), float4(42.0f, 21.0f, 6.0f, -5.0f))"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_Complex_F16) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_Complex_F16) {
     // mat4x4<f16>(
     //     vec4<f16>(2.0h, 3.0h, 4.0h, 8.0h),
     //     vec4<f16>(),
@@ -300,10 +300,10 @@
     auto* vector_identical_init =
         vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
 
-    auto* initializer = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
+    auto* constructor = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
                                     vector_identical_init);
 
-    WrapInFunction(initializer);
+    WrapInFunction(constructor);
 
     GeneratorImpl& gen = Build();
 
@@ -313,7 +313,7 @@
                                         "half4(7.0h), half4(42.0h, 21.0h, 6.0h, -5.0h))"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_Empty_F32) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_Empty_F32) {
     WrapInFunction(mat2x3<f32>());
 
     GeneratorImpl& gen = Build();
@@ -324,7 +324,7 @@
                 HasSubstr("float2x3 const tint_symbol = float2x3(float3(0.0f), float3(0.0f))"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_Empty_F16) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>());
@@ -337,7 +337,7 @@
                 HasSubstr("half2x3 const tint_symbol = half2x3(half3(0.0h), half3(0.0h))"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_Identity_F32) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_Identity_F32) {
     // fn f() {
     //     var m_1: mat4x4<f32> = mat4x4<f32>();
     //     var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
@@ -355,7 +355,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("float4x4 m_2 = float4x4(m_1);"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_Identity_F16) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_Identity_F16) {
     // fn f() {
     //     var m_1: mat4x4<f16> = mat4x4<f16>();
     //     var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
@@ -375,7 +375,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("half4x4 m_2 = half4x4(m_1);"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Array) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Array) {
     WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
                         vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
 
@@ -386,7 +386,7 @@
                                         "float3(7.0f, 8.0f, 9.0f)}"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Struct) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Struct) {
     auto* str = Structure("S", utils::Vector{
                                    Member("a", ty.i32()),
                                    Member("b", ty.f32()),
@@ -401,7 +401,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("{.a=1, .b=2.0f, .c=int3(3, 4, 5)}"));
 }
 
-TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Struct_Empty) {
+TEST_F(MslGeneratorImplTest_Constructor, Type_Struct_Empty) {
     auto* str = Structure("S", utils::Vector{
                                    Member("a", ty.i32()),
                                    Member("b", ty.f32()),
diff --git a/src/tint/writer/msl/generator_impl_function_test.cc b/src/tint/writer/msl/generator_impl_function_test.cc
index de88ecb..3eb809b 100644
--- a/src/tint/writer/msl/generator_impl_function_test.cc
+++ b/src/tint/writer/msl/generator_impl_function_test.cc
@@ -341,8 +341,8 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Group(0_a),
-              Binding(0_a));
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Group(0_a), Binding(0_a));
 
     auto* var = Var("v", ty.f32(), MemberAccessor("coord", "b"));
 
@@ -380,8 +380,8 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Group(0_a),
-              Binding(0_a));
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead,
+              Group(0_a), Binding(0_a));
 
     auto* var = Var("v", ty.f32(), MemberAccessor("coord", "b"));
 
@@ -416,7 +416,7 @@
 TEST_F(MslGeneratorImplTest, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
     auto* ubo_ty = Structure("UBO", utils::Vector{Member("coord", ty.vec4<f32>())});
     auto* ubo =
-        GlobalVar("ubo", ty.Of(ubo_ty), type::AddressSpace::kUniform, Group(0_a), Binding(0_a));
+        GlobalVar("ubo", ty.Of(ubo_ty), builtin::AddressSpace::kUniform, Group(0_a), Binding(0_a));
 
     Func("sub_func",
          utils::Vector{
@@ -466,8 +466,8 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Group(0_a),
-              Binding(0_a));
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Group(0_a), Binding(0_a));
 
     Func("sub_func",
          utils::Vector{
@@ -518,8 +518,8 @@
                                     Member("b", ty.f32()),
                                 });
 
-    GlobalVar("coord", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Group(0_a),
-              Binding(0_a));
+    GlobalVar("coord", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead,
+              Group(0_a), Binding(0_a));
 
     Func("sub_func",
          utils::Vector{
@@ -656,8 +656,8 @@
 
     auto* s = Structure("Data", utils::Vector{Member("d", ty.f32())});
 
-    GlobalVar("data", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Group(0_a),
-              Binding(0_a));
+    GlobalVar("data", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Group(0_a), Binding(0_a));
 
     {
         auto* var = Var("v", ty.f32(), MemberAccessor("data", "d"));
diff --git a/src/tint/writer/msl/generator_impl_import_test.cc b/src/tint/writer/msl/generator_impl_import_test.cc
index 6fd95ae..d00acd5 100644
--- a/src/tint/writer/msl/generator_impl_import_test.cc
+++ b/src/tint/writer/msl/generator_impl_import_test.cc
@@ -234,7 +234,7 @@
                                          MslImportData{"clamp", "clamp"}));
 
 TEST_F(MslGeneratorImplTest, MslImportData_Determinant) {
-    GlobalVar("var", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("var", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("determinant", "var");
 
@@ -248,7 +248,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, MslImportData_QuantizeToF16_Scalar) {
-    GlobalVar("v", Expr(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", Expr(2_f), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("quantizeToF16", "v");
     WrapInFunction(expr);
@@ -261,7 +261,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, MslImportData_QuantizeToF16_Vector) {
-    GlobalVar("v", vec3<f32>(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec3<f32>(2_f), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("quantizeToF16", "v");
     WrapInFunction(expr);
diff --git a/src/tint/writer/msl/generator_impl_loop_test.cc b/src/tint/writer/msl/generator_impl_loop_test.cc
index cac1306..6d2959c 100644
--- a/src/tint/writer/msl/generator_impl_loop_test.cc
+++ b/src/tint/writer/msl/generator_impl_loop_test.cc
@@ -93,8 +93,8 @@
 TEST_F(MslGeneratorImplTest, Emit_LoopNestedWithContinuing) {
     Func("a_statement", {}, ty.void_(), utils::Empty);
 
-    GlobalVar("lhs", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("rhs", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("lhs", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
@@ -139,7 +139,7 @@
     // }
     //
 
-    GlobalVar("rhs", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("rhs", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4_f))),  //
                        Decl(Var("other", ty.f32())),             //
@@ -216,7 +216,7 @@
     Func("f", utils::Vector{Param("i", ty.i32())}, ty.void_(), utils::Empty);
     auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
 
-    GlobalVar("a", ty.atomic<i32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic<i32>(), builtin::AddressSpace::kWorkgroup);
     auto* multi_stmt = Block(f(1_i), f(2_i));
     auto* loop = For(multi_stmt, nullptr, nullptr,  //
                      Block(Return()));
@@ -292,7 +292,7 @@
     Func("f", utils::Vector{Param("i", ty.i32())}, ty.void_(), utils::Empty);
     auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
 
-    GlobalVar("a", ty.atomic<i32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic<i32>(), builtin::AddressSpace::kWorkgroup);
     auto* multi_stmt = Block(f(1_i), f(2_i));
     auto* loop = For(nullptr, nullptr, multi_stmt,  //
                      Block(Return()));
@@ -347,7 +347,7 @@
     Func("f", utils::Vector{Param("i", ty.i32())}, ty.void_(), utils::Empty);
     auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
 
-    GlobalVar("a", ty.atomic<i32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic<i32>(), builtin::AddressSpace::kWorkgroup);
     auto* multi_stmt_a = Block(f(1_i), f(2_i));
     auto* multi_stmt_b = Block(f(3_i), f(4_i));
     auto* loop = For(multi_stmt_a, Expr(true), multi_stmt_b,  //
diff --git a/src/tint/writer/msl/generator_impl_member_accessor_test.cc b/src/tint/writer/msl/generator_impl_member_accessor_test.cc
index 0b54a52..1e1136e 100644
--- a/src/tint/writer/msl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/msl/generator_impl_member_accessor_test.cc
@@ -21,7 +21,7 @@
 
 TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor) {
     GlobalVar("str", ty.Of(Structure("my_str", utils::Vector{Member("mem", ty.f32())})),
-              type::AddressSpace::kPrivate);
+              builtin::AddressSpace::kPrivate);
     auto* expr = MemberAccessor("str", "mem");
     WrapInFunction(expr);
 
@@ -33,7 +33,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor_Swizzle_xyz) {
-    GlobalVar("my_vec", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = MemberAccessor("my_vec", "xyz");
     WrapInFunction(expr);
@@ -45,7 +45,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor_Swizzle_gbr) {
-    GlobalVar("my_vec", ty.vec4<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("my_vec", ty.vec4<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* expr = MemberAccessor("my_vec", "gbr");
     WrapInFunction(expr);
diff --git a/src/tint/writer/msl/generator_impl_sanitizer_test.cc b/src/tint/writer/msl/generator_impl_sanitizer_test.cc
index 3b35e6d..f72e0e9 100644
--- a/src/tint/writer/msl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/msl/generator_impl_sanitizer_test.cc
@@ -28,7 +28,7 @@
 
 TEST_F(MslSanitizerTest, Call_ArrayLength) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
@@ -82,7 +82,7 @@
                                          Member(0, "z", ty.f32()),
                                          Member(4, "a", ty.array<f32>()),
                                      });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
@@ -135,7 +135,7 @@
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_ViaLets) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     auto* p = Let("p", AddressOf("b"));
@@ -192,9 +192,9 @@
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(0_a));
-    GlobalVar("c", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(2_a),
+    GlobalVar("c", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(2_a),
               Group(0_a));
 
     Func("a_func", utils::Empty, ty.void_(),
@@ -251,9 +251,9 @@
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniformMissingBinding) {
     auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(0_a));
-    GlobalVar("c", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(2_a),
+    GlobalVar("c", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(2_a),
               Group(0_a));
 
     Func("a_func", utils::Empty, ty.void_(),
diff --git a/src/tint/writer/msl/generator_impl_test.cc b/src/tint/writer/msl/generator_impl_test.cc
index 71d5858..52ae381 100644
--- a/src/tint/writer/msl/generator_impl_test.cc
+++ b/src/tint/writer/msl/generator_impl_test.cc
@@ -163,7 +163,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, WorkgroupMatrix) {
-    GlobalVar("m", ty.mat2x2<f32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("m", ty.mat2x2<f32>(), builtin::AddressSpace::kWorkgroup);
     Func("comp_main", utils::Empty, ty.void_(), utils::Vector{Decl(Let("x", Expr("m")))},
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -203,7 +203,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, WorkgroupMatrixInArray) {
-    GlobalVar("m", ty.array(ty.mat2x2<f32>(), 4_i), type::AddressSpace::kWorkgroup);
+    GlobalVar("m", ty.array(ty.mat2x2<f32>(), 4_i), builtin::AddressSpace::kWorkgroup);
     Func("comp_main", utils::Empty, ty.void_(), utils::Vector{Decl(Let("x", Expr("m")))},
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -264,7 +264,7 @@
     Structure("S2", utils::Vector{
                         Member("s", ty("S1")),
                     });
-    GlobalVar("s", ty("S2"), type::AddressSpace::kWorkgroup);
+    GlobalVar("s", ty("S2"), builtin::AddressSpace::kWorkgroup);
     Func("comp_main", utils::Empty, ty.void_(), utils::Vector{Decl(Let("x", Expr("s")))},
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -314,15 +314,15 @@
 }
 
 TEST_F(MslGeneratorImplTest, WorkgroupMatrix_Multiples) {
-    GlobalVar("m1", ty.mat2x2<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("m2", ty.mat2x3<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("m3", ty.mat2x4<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("m4", ty.mat3x2<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("m5", ty.mat3x3<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("m6", ty.mat3x4<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("m7", ty.mat4x2<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("m8", ty.mat4x3<f32>(), type::AddressSpace::kWorkgroup);
-    GlobalVar("m9", ty.mat4x4<f32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("m1", ty.mat2x2<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("m2", ty.mat2x3<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("m3", ty.mat2x4<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("m4", ty.mat3x2<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("m5", ty.mat3x3<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("m6", ty.mat3x4<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("m7", ty.mat4x2<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("m8", ty.mat4x3<f32>(), builtin::AddressSpace::kWorkgroup);
+    GlobalVar("m9", ty.mat4x4<f32>(), builtin::AddressSpace::kWorkgroup);
     Func("main1", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("a1", Expr("m1"))),
diff --git a/src/tint/writer/msl/generator_impl_type_test.cc b/src/tint/writer/msl/generator_impl_type_test.cc
index 971d2a6..9775cf9 100644
--- a/src/tint/writer/msl/generator_impl_type_test.cc
+++ b/src/tint/writer/msl/generator_impl_type_test.cc
@@ -90,7 +90,7 @@
 
 TEST_F(MslGeneratorImplTest, EmitType_Array) {
     auto arr = ty.array<bool, 4>();
-    ast::Type type = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type type = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
@@ -102,7 +102,7 @@
 TEST_F(MslGeneratorImplTest, EmitType_ArrayOfArray) {
     auto a = ty.array<bool, 4>();
     auto b = ty.array(a, 5_u);
-    ast::Type type = GlobalVar("G", b, type::AddressSpace::kPrivate)->type;
+    ast::Type type = GlobalVar("G", b, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
@@ -115,7 +115,7 @@
     auto a = ty.array<bool, 4>();
     auto b = ty.array(a, 5_u);
     auto c = ty.array(b, 6_u);
-    ast::Type type = GlobalVar("G", c, type::AddressSpace::kPrivate)->type;
+    ast::Type type = GlobalVar("G", c, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
@@ -126,7 +126,7 @@
 
 TEST_F(MslGeneratorImplTest, EmitType_Array_WithoutName) {
     auto arr = ty.array<bool, 4>();
-    ast::Type type = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type type = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
@@ -137,7 +137,7 @@
 
 TEST_F(MslGeneratorImplTest, EmitType_RuntimeArray) {
     auto arr = ty.array<bool, 1>();
-    ast::Type type = GlobalVar("G", arr, type::AddressSpace::kPrivate)->type;
+    ast::Type type = GlobalVar("G", arr, builtin::AddressSpace::kPrivate)->type;
 
     GeneratorImpl& gen = Build();
 
@@ -212,7 +212,8 @@
 
 TEST_F(MslGeneratorImplTest, EmitType_Pointer) {
     auto* f32 = create<type::F32>();
-    auto* p = create<type::Pointer>(f32, type::AddressSpace::kWorkgroup, type::Access::kReadWrite);
+    auto* p =
+        create<type::Pointer>(f32, builtin::AddressSpace::kWorkgroup, builtin::Access::kReadWrite);
 
     GeneratorImpl& gen = Build();
 
@@ -283,8 +284,8 @@
                  Member("z", ty.f32()),
              });
 
-    ast::Type type = GlobalVar("G", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-                               Binding(0_a), Group(0_a))
+    ast::Type type = GlobalVar("G", ty.Of(s), builtin::AddressSpace::kStorage,
+                               builtin::Access::kRead, Binding(0_a), Group(0_a))
                          ->type;
 
     GeneratorImpl& gen = Build();
@@ -392,8 +393,8 @@
                                  Member("e", ty.f32()),
                              });
 
-    ast::Type type = GlobalVar("G", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-                               Binding(0_a), Group(0_a))
+    ast::Type type = GlobalVar("G", ty.Of(s), builtin::AddressSpace::kStorage,
+                               builtin::Access::kRead, Binding(0_a), Group(0_a))
                          ->type;
 
     GeneratorImpl& gen = Build();
@@ -484,8 +485,8 @@
                                  Member("f", array_z),
                              });
 
-    ast::Type type = GlobalVar("G", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-                               Binding(0_a), Group(0_a))
+    ast::Type type = GlobalVar("G", ty.Of(s), builtin::AddressSpace::kStorage,
+                               builtin::Access::kRead, Binding(0_a), Group(0_a))
                          ->type;
 
     GeneratorImpl& gen = Build();
@@ -568,8 +569,8 @@
                                  Member("c", ty.i32()),
                              });
 
-    ast::Type type = GlobalVar("G", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-                               Binding(0_a), Group(0_a))
+    ast::Type type = GlobalVar("G", ty.Of(s), builtin::AddressSpace::kStorage,
+                               builtin::Access::kRead, Binding(0_a), Group(0_a))
                          ->type;
 
     GeneratorImpl& gen = Build();
@@ -630,8 +631,8 @@
                                  Member("tint_pad_21", ty.f32()),
                              });
 
-    ast::Type type = GlobalVar("G", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-                               Binding(0_a), Group(0_a))
+    ast::Type type = GlobalVar("G", ty.Of(s), builtin::AddressSpace::kStorage,
+                               builtin::Access::kRead, Binding(0_a), Group(0_a))
                          ->type;
 
     GeneratorImpl& gen = Build();
@@ -689,8 +690,8 @@
                                  Member("b", ty.f32()),
                              });
 
-    ast::Type type = GlobalVar("G", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
-                               Binding(0_a), Group(0_a))
+    ast::Type type = GlobalVar("G", ty.Of(s), builtin::AddressSpace::kStorage,
+                               builtin::Access::kRead, Binding(0_a), Group(0_a))
                          ->type;
 
     GeneratorImpl& gen = Build();
@@ -853,7 +854,8 @@
 TEST_P(MslStorageTexturesTest, Emit) {
     auto params = GetParam();
 
-    auto s = ty.storage_texture(params.dim, type::TexelFormat::kR32Float, type::Access::kWrite);
+    auto s =
+        ty.storage_texture(params.dim, builtin::TexelFormat::kR32Float, builtin::Access::kWrite);
     ast::Type type = GlobalVar("test_var", s, Binding(0_a), Group(0_a))->type;
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/msl/generator_impl_unary_op_test.cc b/src/tint/writer/msl/generator_impl_unary_op_test.cc
index ff4ac50..95801a8 100644
--- a/src/tint/writer/msl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/msl/generator_impl_unary_op_test.cc
@@ -20,7 +20,7 @@
 using MslUnaryOpTest = TestHelper;
 
 TEST_F(MslUnaryOpTest, AddressOf) {
-    GlobalVar("expr", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
     WrapInFunction(op);
 
@@ -32,7 +32,7 @@
 }
 
 TEST_F(MslUnaryOpTest, Complement) {
-    GlobalVar("expr", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
     WrapInFunction(op);
 
@@ -44,7 +44,7 @@
 }
 
 TEST_F(MslUnaryOpTest, Indirection) {
-    GlobalVar("G", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("G", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* p = Let("expr", create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
     WrapInFunction(p, op);
@@ -57,7 +57,7 @@
 }
 
 TEST_F(MslUnaryOpTest, Not) {
-    GlobalVar("expr", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.bool_(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
     WrapInFunction(op);
 
@@ -69,7 +69,7 @@
 }
 
 TEST_F(MslUnaryOpTest, Negation) {
-    GlobalVar("expr", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
     WrapInFunction(op);
 
diff --git a/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
index 1386abb..fa0c53f 100644
--- a/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -518,7 +518,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Private) {
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
 
     WrapInFunction(Expr("a"));
 
@@ -531,7 +531,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Workgroup) {
-    GlobalVar("a", ty.f32(), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kWorkgroup);
 
     WrapInFunction(Expr("a"));
 
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 7482558..ad0d746 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -33,8 +33,8 @@
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/switch_statement.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/type_initializer.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/transform/add_block_attribute.h"
 #include "src/tint/type/array.h"
@@ -506,8 +506,8 @@
     for (const auto* var : func_sem->TransitivelyReferencedGlobals()) {
         // For SPIR-V 1.3 we only output Input/output variables. If we update to
         // SPIR-V 1.4 or later this should be all variables.
-        if (var->AddressSpace() != type::AddressSpace::kIn &&
-            var->AddressSpace() != type::AddressSpace::kOut) {
+        if (var->AddressSpace() != builtin::AddressSpace::kIn &&
+            var->AddressSpace() != builtin::AddressSpace::kOut) {
             continue;
         }
 
@@ -548,8 +548,9 @@
              Operand(wgsize[0].value()), Operand(wgsize[1].value()), Operand(wgsize[2].value())});
     }
 
-    for (auto builtin : func_sem->TransitivelyReferencedBuiltinVariables()) {
-        if (builtin.second->builtin == builtin::BuiltinValue::kFragDepth) {
+    for (auto it : func_sem->TransitivelyReferencedBuiltinVariables()) {
+        auto builtin = builder_.Sem().Get(it.second)->Value();
+        if (builtin == builtin::BuiltinValue::kFragDepth) {
             push_execution_mode(spv::Op::OpExecutionMode,
                                 {Operand(id), U32Operand(SpvExecutionModeDepthReplacing)});
         }
@@ -718,7 +719,7 @@
 
     auto result = result_op();
     auto var_id = std::get<uint32_t>(result);
-    auto sc = type::AddressSpace::kFunction;
+    auto sc = builtin::AddressSpace::kFunction;
     auto* type = sem->Type();
     auto type_id = GenerateTypeIfNeeded(type);
     if (type_id == 0) {
@@ -769,7 +770,7 @@
 
     uint32_t init_id = 0;
     if (auto* ctor = v->initializer) {
-        init_id = GenerateInitializerExpression(v, ctor);
+        init_id = GenerateConstructorExpression(v, ctor);
         if (init_id == 0) {
             return false;
         }
@@ -778,8 +779,9 @@
     auto result = result_op();
     auto var_id = std::get<uint32_t>(result);
 
-    auto sc = sem->AddressSpace() == type::AddressSpace::kNone ? type::AddressSpace::kPrivate
-                                                               : sem->AddressSpace();
+    auto sc = sem->AddressSpace() == builtin::AddressSpace::kUndefined
+                  ? builtin::AddressSpace::kPrivate
+                  : sem->AddressSpace();
 
     auto type_id = GenerateTypeIfNeeded(sem->Type());
     if (type_id == 0) {
@@ -799,16 +801,16 @@
             // type is a sem::Struct or a type::StorageTexture
             auto access = st ? st->access() : sem->Access();
             switch (access) {
-                case type::Access::kWrite:
+                case builtin::Access::kWrite:
                     push_annot(spv::Op::OpDecorate,
                                {Operand(var_id), U32Operand(SpvDecorationNonReadable)});
                     break;
-                case type::Access::kRead:
+                case builtin::Access::kRead:
                     push_annot(spv::Op::OpDecorate,
                                {Operand(var_id), U32Operand(SpvDecorationNonWritable)});
                     break;
-                case type::Access::kUndefined:
-                case type::Access::kReadWrite:
+                case builtin::Access::kUndefined:
+                case builtin::Access::kReadWrite:
                     break;
             }
         }
@@ -818,10 +820,10 @@
             // If we're a Workgroup variable, and the
             // VK_KHR_zero_initialize_workgroup_memory extension is enabled, we should
             // also zero-initialize.
-            if (sem->AddressSpace() == type::AddressSpace::kPrivate ||
-                sem->AddressSpace() == type::AddressSpace::kOut ||
+            if (sem->AddressSpace() == builtin::AddressSpace::kPrivate ||
+                sem->AddressSpace() == builtin::AddressSpace::kOut ||
                 (zero_initialize_workgroup_memory_ &&
-                 sem->AddressSpace() == type::AddressSpace::kWorkgroup)) {
+                 sem->AddressSpace() == builtin::AddressSpace::kWorkgroup)) {
                 init_id = GenerateConstantNullIfNeeded(type);
                 if (init_id == 0) {
                     return 0;
@@ -836,10 +838,11 @@
     for (auto* attr : v->attributes) {
         bool ok = Switch(
             attr,
-            [&](const ast::BuiltinAttribute* builtin) {
+            [&](const ast::BuiltinAttribute* builtin_attr) {
+                auto builtin = builder_.Sem().Get(builtin_attr)->Value();
                 push_annot(spv::Op::OpDecorate,
                            {Operand(var_id), U32Operand(SpvDecorationBuiltIn),
-                            U32Operand(ConvertBuiltin(builtin->builtin, sem->AddressSpace()))});
+                            U32Operand(ConvertBuiltin(builtin, sem->AddressSpace()))});
                 return true;
             },
             [&](const ast::LocationAttribute*) {
@@ -848,7 +851,19 @@
                 return true;
             },
             [&](const ast::InterpolateAttribute* interpolate) {
-                AddInterpolationDecorations(var_id, interpolate->type, interpolate->sampling);
+                auto& s = builder_.Sem();
+                auto i_type =
+                    s.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(interpolate->type)
+                        ->Value();
+
+                auto i_smpl = builtin::InterpolationSampling::kUndefined;
+                if (interpolate->sampling) {
+                    i_smpl = s.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
+                                  interpolate->sampling)
+                                 ->Value();
+                }
+
+                AddInterpolationDecorations(var_id, i_type, i_smpl);
                 return true;
             },
             [&](const ast::InvariantAttribute*) {
@@ -1232,7 +1247,7 @@
     return id;
 }
 
-uint32_t Builder::GenerateInitializerExpression(const ast::Variable* var,
+uint32_t Builder::GenerateConstructorExpression(const ast::Variable* var,
                                                 const ast::Expression* expr) {
     if (auto* sem = builder_.Sem().GetVal(expr)) {
         if (auto constant = sem->ConstantValue()) {
@@ -1240,15 +1255,15 @@
         }
     }
     if (auto* call = builder_.Sem().Get<sem::Call>(expr)) {
-        if (call->Target()->IsAnyOf<sem::TypeInitializer, sem::TypeConversion>()) {
-            return GenerateTypeInitializerOrConversion(call, var);
+        if (call->Target()->IsAnyOf<sem::ValueConstructor, sem::ValueConversion>()) {
+            return GenerateValueConstructorOrConversion(call, var);
         }
     }
-    error_ = "unknown initializer expression";
+    error_ = "unknown constructor expression";
     return 0;
 }
 
-bool Builder::IsInitializerConst(const ast::Expression* expr) {
+bool Builder::IsConstructorConst(const ast::Expression* expr) {
     bool is_const = true;
     ast::TraverseExpressions(expr, builder_.Diagnostics(), [&](const ast::Expression* e) {
         if (e->Is<ast::LiteralExpression>()) {
@@ -1262,7 +1277,7 @@
                 return ast::TraverseAction::Skip;
             }
             auto* call = sem->As<sem::Call>();
-            if (call->Target()->Is<sem::TypeInitializer>()) {
+            if (call->Target()->Is<sem::ValueConstructor>()) {
                 return ast::TraverseAction::Descend;
             }
         }
@@ -1273,19 +1288,19 @@
     return is_const;
 }
 
-uint32_t Builder::GenerateTypeInitializerOrConversion(const sem::Call* call,
-                                                      const ast::Variable* var) {
+uint32_t Builder::GenerateValueConstructorOrConversion(const sem::Call* call,
+                                                       const ast::Variable* var) {
     auto& args = call->Arguments();
     auto* global_var = builder_.Sem().Get<sem::GlobalVariable>(var);
     auto* result_type = call->Type();
 
-    // Generate the zero initializer if there are no values provided.
+    // Generate the zero constructor if there are no values provided.
     if (args.IsEmpty()) {
         return GenerateConstantNullIfNeeded(result_type->UnwrapRef());
     }
 
     result_type = result_type->UnwrapRef();
-    bool initializer_is_const = IsInitializerConst(call->Declaration());
+    bool constructor_is_const = IsConstructorConst(call->Declaration());
     if (has_error()) {
         return 0;
     }
@@ -1320,7 +1335,7 @@
         return 0;
     }
 
-    bool result_is_constant_composite = initializer_is_const;
+    bool result_is_constant_composite = constructor_is_const;
     bool result_is_spec_composite = false;
 
     if (auto* vec = result_type->As<type::Vector>()) {
@@ -1900,9 +1915,9 @@
     // Create a new vector to splat scalar into
     auto splat_vector = result_op();
     auto* splat_vector_type = builder_.create<type::Pointer>(
-        vec_type, type::AddressSpace::kFunction, type::Access::kReadWrite);
+        vec_type, builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
     push_function_var({Operand(GenerateTypeIfNeeded(splat_vector_type)), splat_vector,
-                       U32Operand(ConvertAddressSpace(type::AddressSpace::kFunction)),
+                       U32Operand(ConvertAddressSpace(builtin::AddressSpace::kFunction)),
                        Operand(GenerateConstantNullIfNeeded(vec_type))});
 
     // Splat scalar into vector
@@ -2228,13 +2243,14 @@
     auto* call = builder_.Sem().Get<sem::Call>(expr);
     auto* target = call->Target();
     return Switch(
-        target, [&](const sem::Function* func) { return GenerateFunctionCall(call, func); },
+        target,  //
+        [&](const sem::Function* func) { return GenerateFunctionCall(call, func); },
         [&](const sem::Builtin* builtin) { return GenerateBuiltinCall(call, builtin); },
-        [&](const sem::TypeConversion*) {
-            return GenerateTypeInitializerOrConversion(call, nullptr);
+        [&](const sem::ValueConversion*) {
+            return GenerateValueConstructorOrConversion(call, nullptr);
         },
-        [&](const sem::TypeInitializer*) {
-            return GenerateTypeInitializerOrConversion(call, nullptr);
+        [&](const sem::ValueConstructor*) {
+            return GenerateValueConstructorOrConversion(call, nullptr);
         },
         [&](Default) {
             TINT_ICE(Writer, builder_.Diagnostics())
@@ -3069,11 +3085,11 @@
 
     uint32_t memory_id = 0;
     switch (builtin->Parameters()[0]->Type()->As<type::Pointer>()->AddressSpace()) {
-        case type::AddressSpace::kWorkgroup:
+        case builtin::AddressSpace::kWorkgroup:
             memory_id = GenerateConstantIfNeeded(
                 ScalarConstant::U32(static_cast<uint32_t>(spv::Scope::Workgroup)));
             break;
-        case type::AddressSpace::kStorage:
+        case builtin::AddressSpace::kStorage:
             memory_id = GenerateConstantIfNeeded(
                 ScalarConstant::U32(static_cast<uint32_t>(spv::Scope::Device)));
             break;
@@ -3656,10 +3672,10 @@
     // fine.
     if (auto* ptr = type->As<type::Pointer>()) {
         type = builder_.create<type::Pointer>(ptr->StoreType(), ptr->AddressSpace(),
-                                              type::Access::kReadWrite);
+                                              builtin::Access::kReadWrite);
     } else if (auto* ref = type->As<type::Reference>()) {
         type = builder_.create<type::Pointer>(ref->StoreType(), ref->AddressSpace(),
-                                              type::Access::kReadWrite);
+                                              builtin::Access::kReadWrite);
     }
 
     return utils::GetOrCreate(type_to_id_, type, [&]() -> uint32_t {
@@ -3718,11 +3734,12 @@
                 // SPIR-V, we must output a single type, while the variable is
                 // annotated with the access type. Doing this ensures we de-dupe.
                 type_to_id_[builder_.create<type::StorageTexture>(
-                    tex->dim(), tex->texel_format(), type::Access::kRead, tex->type())] = id;
+                    tex->dim(), tex->texel_format(), builtin::Access::kRead, tex->type())] = id;
                 type_to_id_[builder_.create<type::StorageTexture>(
-                    tex->dim(), tex->texel_format(), type::Access::kWrite, tex->type())] = id;
+                    tex->dim(), tex->texel_format(), builtin::Access::kWrite, tex->type())] = id;
                 type_to_id_[builder_.create<type::StorageTexture>(
-                    tex->dim(), tex->texel_format(), type::Access::kReadWrite, tex->type())] = id;
+                    tex->dim(), tex->texel_format(), builtin::Access::kReadWrite, tex->type())] =
+                    id;
                 return true;
             },
             [&](const type::Texture* tex) { return GenerateTextureType(tex, result); },
@@ -3976,40 +3993,38 @@
     return true;
 }
 
-SpvStorageClass Builder::ConvertAddressSpace(type::AddressSpace klass) const {
+SpvStorageClass Builder::ConvertAddressSpace(builtin::AddressSpace klass) const {
     switch (klass) {
-        case type::AddressSpace::kUndefined:
-            return SpvStorageClassMax;
-        case type::AddressSpace::kIn:
+        case builtin::AddressSpace::kIn:
             return SpvStorageClassInput;
-        case type::AddressSpace::kOut:
+        case builtin::AddressSpace::kOut:
             return SpvStorageClassOutput;
-        case type::AddressSpace::kUniform:
+        case builtin::AddressSpace::kUniform:
             return SpvStorageClassUniform;
-        case type::AddressSpace::kWorkgroup:
+        case builtin::AddressSpace::kWorkgroup:
             return SpvStorageClassWorkgroup;
-        case type::AddressSpace::kPushConstant:
+        case builtin::AddressSpace::kPushConstant:
             return SpvStorageClassPushConstant;
-        case type::AddressSpace::kHandle:
+        case builtin::AddressSpace::kHandle:
             return SpvStorageClassUniformConstant;
-        case type::AddressSpace::kStorage:
+        case builtin::AddressSpace::kStorage:
             return SpvStorageClassStorageBuffer;
-        case type::AddressSpace::kPrivate:
+        case builtin::AddressSpace::kPrivate:
             return SpvStorageClassPrivate;
-        case type::AddressSpace::kFunction:
+        case builtin::AddressSpace::kFunction:
             return SpvStorageClassFunction;
-        case type::AddressSpace::kNone:
+        case builtin::AddressSpace::kUndefined:
             break;
     }
     return SpvStorageClassMax;
 }
 
-SpvBuiltIn Builder::ConvertBuiltin(builtin::BuiltinValue builtin, type::AddressSpace storage) {
+SpvBuiltIn Builder::ConvertBuiltin(builtin::BuiltinValue builtin, builtin::AddressSpace storage) {
     switch (builtin) {
         case builtin::BuiltinValue::kPosition:
-            if (storage == type::AddressSpace::kIn) {
+            if (storage == builtin::AddressSpace::kIn) {
                 return SpvBuiltInFragCoord;
-            } else if (TINT_LIKELY(storage == type::AddressSpace::kOut)) {
+            } else if (TINT_LIKELY(storage == builtin::AddressSpace::kOut)) {
                 return SpvBuiltInPosition;
             } else {
                 TINT_ICE(Writer, builder_.Diagnostics()) << "invalid address space for builtin";
@@ -4047,75 +4062,75 @@
 }
 
 void Builder::AddInterpolationDecorations(uint32_t id,
-                                          ast::InterpolationType type,
-                                          ast::InterpolationSampling sampling) {
+                                          builtin::InterpolationType type,
+                                          builtin::InterpolationSampling sampling) {
     switch (type) {
-        case ast::InterpolationType::kLinear:
+        case builtin::InterpolationType::kLinear:
             push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationNoPerspective)});
             break;
-        case ast::InterpolationType::kFlat:
+        case builtin::InterpolationType::kFlat:
             push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationFlat)});
             break;
-        case ast::InterpolationType::kPerspective:
-        case ast::InterpolationType::kUndefined:
+        case builtin::InterpolationType::kPerspective:
+        case builtin::InterpolationType::kUndefined:
             break;
     }
     switch (sampling) {
-        case ast::InterpolationSampling::kCentroid:
+        case builtin::InterpolationSampling::kCentroid:
             push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationCentroid)});
             break;
-        case ast::InterpolationSampling::kSample:
+        case builtin::InterpolationSampling::kSample:
             push_capability(SpvCapabilitySampleRateShading);
             push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationSample)});
             break;
-        case ast::InterpolationSampling::kCenter:
-        case ast::InterpolationSampling::kUndefined:
+        case builtin::InterpolationSampling::kCenter:
+        case builtin::InterpolationSampling::kUndefined:
             break;
     }
 }
 
-SpvImageFormat Builder::convert_texel_format_to_spv(const type::TexelFormat format) {
+SpvImageFormat Builder::convert_texel_format_to_spv(const builtin::TexelFormat format) {
     switch (format) {
-        case type::TexelFormat::kBgra8Unorm:
+        case builtin::TexelFormat::kBgra8Unorm:
             TINT_ICE(Writer, builder_.Diagnostics())
                 << "bgra8unorm should have been polyfilled to rgba8unorm";
             return SpvImageFormatUnknown;
-        case type::TexelFormat::kR32Uint:
+        case builtin::TexelFormat::kR32Uint:
             return SpvImageFormatR32ui;
-        case type::TexelFormat::kR32Sint:
+        case builtin::TexelFormat::kR32Sint:
             return SpvImageFormatR32i;
-        case type::TexelFormat::kR32Float:
+        case builtin::TexelFormat::kR32Float:
             return SpvImageFormatR32f;
-        case type::TexelFormat::kRgba8Unorm:
+        case builtin::TexelFormat::kRgba8Unorm:
             return SpvImageFormatRgba8;
-        case type::TexelFormat::kRgba8Snorm:
+        case builtin::TexelFormat::kRgba8Snorm:
             return SpvImageFormatRgba8Snorm;
-        case type::TexelFormat::kRgba8Uint:
+        case builtin::TexelFormat::kRgba8Uint:
             return SpvImageFormatRgba8ui;
-        case type::TexelFormat::kRgba8Sint:
+        case builtin::TexelFormat::kRgba8Sint:
             return SpvImageFormatRgba8i;
-        case type::TexelFormat::kRg32Uint:
+        case builtin::TexelFormat::kRg32Uint:
             push_capability(SpvCapabilityStorageImageExtendedFormats);
             return SpvImageFormatRg32ui;
-        case type::TexelFormat::kRg32Sint:
+        case builtin::TexelFormat::kRg32Sint:
             push_capability(SpvCapabilityStorageImageExtendedFormats);
             return SpvImageFormatRg32i;
-        case type::TexelFormat::kRg32Float:
+        case builtin::TexelFormat::kRg32Float:
             push_capability(SpvCapabilityStorageImageExtendedFormats);
             return SpvImageFormatRg32f;
-        case type::TexelFormat::kRgba16Uint:
+        case builtin::TexelFormat::kRgba16Uint:
             return SpvImageFormatRgba16ui;
-        case type::TexelFormat::kRgba16Sint:
+        case builtin::TexelFormat::kRgba16Sint:
             return SpvImageFormatRgba16i;
-        case type::TexelFormat::kRgba16Float:
+        case builtin::TexelFormat::kRgba16Float:
             return SpvImageFormatRgba16f;
-        case type::TexelFormat::kRgba32Uint:
+        case builtin::TexelFormat::kRgba32Uint:
             return SpvImageFormatRgba32ui;
-        case type::TexelFormat::kRgba32Sint:
+        case builtin::TexelFormat::kRgba32Sint:
             return SpvImageFormatRgba32i;
-        case type::TexelFormat::kRgba32Float:
+        case builtin::TexelFormat::kRgba32Float:
             return SpvImageFormatRgba32f;
-        case type::TexelFormat::kUndefined:
+        case builtin::TexelFormat::kUndefined:
             return SpvImageFormatUnknown;
     }
     return SpvImageFormatUnknown;
diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h
index c56085a..53fb108 100644
--- a/src/tint/writer/spirv/builder.h
+++ b/src/tint/writer/spirv/builder.h
@@ -33,6 +33,7 @@
 #include "src/tint/ast/switch_statement.h"
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/scope_stack.h"
 #include "src/tint/sem/builtin.h"
@@ -44,8 +45,8 @@
 namespace tint::sem {
 class Call;
 class Load;
-class TypeInitializer;
-class TypeConversion;
+class ValueConstructor;
+class ValueConversion;
 }  // namespace tint::sem
 namespace tint::type {
 class Reference;
@@ -208,12 +209,12 @@
     /// Converts a address space to a SPIR-V address space.
     /// @param klass the address space to convert
     /// @returns the SPIR-V address space or SpvStorageClassMax on error.
-    SpvStorageClass ConvertAddressSpace(type::AddressSpace klass) const;
+    SpvStorageClass ConvertAddressSpace(builtin::AddressSpace klass) const;
     /// Converts a builtin to a SPIR-V builtin and pushes a capability if needed.
     /// @param builtin the builtin to convert
     /// @param storage the address space that this builtin is being used with
     /// @returns the SPIR-V builtin or SpvBuiltInMax on error.
-    SpvBuiltIn ConvertBuiltin(builtin::BuiltinValue builtin, type::AddressSpace storage);
+    SpvBuiltIn ConvertBuiltin(builtin::BuiltinValue builtin, builtin::AddressSpace storage);
 
     /// Converts an interpolate attribute to SPIR-V decorations and pushes a
     /// capability if needed.
@@ -221,8 +222,8 @@
     /// @param type the interpolation type
     /// @param sampling the interpolation sampling
     void AddInterpolationDecorations(uint32_t id,
-                                     ast::InterpolationType type,
-                                     ast::InterpolationSampling sampling);
+                                     builtin::InterpolationType type,
+                                     builtin::InterpolationSampling sampling);
 
     /// Generates the enabling of an extension. Emits an error and returns false if the extension is
     /// not supported.
@@ -337,11 +338,11 @@
     /// instruction set, if one doesn't exist yet, and returns the import ID.
     /// @returns the import ID, or 0 on error.
     uint32_t GetGLSLstd450Import();
-    /// Generates a initializer expression
+    /// Generates a constructor expression
     /// @param var the variable generated for, nullptr if no variable associated.
     /// @param expr the expression to generate
     /// @returns the ID of the expression or 0 on failure.
-    uint32_t GenerateInitializerExpression(const ast::Variable* var, const ast::Expression* expr);
+    uint32_t GenerateConstructorExpression(const ast::Variable* var, const ast::Expression* expr);
     /// Generates a literal constant if needed
     /// @param lit the literal to generate
     /// @returns the ID on success or 0 on failure
@@ -372,11 +373,11 @@
     /// @param builtin the builtin being called
     /// @returns the expression ID on success or 0 otherwise
     uint32_t GenerateBuiltinCall(const sem::Call* call, const sem::Builtin* builtin);
-    /// Handles generating a type initializer or type conversion expression
+    /// Handles generating a value constructor or value conversion expression
     /// @param call the call expression
     /// @param var the variable that is being initialized. May be null.
     /// @returns the expression ID on success or 0 otherwise
-    uint32_t GenerateTypeInitializerOrConversion(const sem::Call* call, const ast::Variable* var);
+    uint32_t GenerateValueConstructorOrConversion(const sem::Call* call, const ast::Variable* var);
     /// Generates a texture builtin call. Emits an error and returns false if
     /// we're currently outside a function.
     /// @param call the call expression
@@ -535,12 +536,12 @@
     /// Converts TexelFormat to SPIR-V and pushes an appropriate capability.
     /// @param format AST image format type
     /// @returns SPIR-V image format type
-    SpvImageFormat convert_texel_format_to_spv(const type::TexelFormat format);
+    SpvImageFormat convert_texel_format_to_spv(const builtin::TexelFormat format);
 
-    /// Determines if the given type initializer is created from constant values
+    /// Determines if the given value constructor is created from constant values
     /// @param expr the expression to check
-    /// @returns true if the initializer is constant
-    bool IsInitializerConst(const ast::Expression* expr);
+    /// @returns true if the constructor is constant
+    bool IsConstructorConst(const ast::Expression* expr);
 
   private:
     /// @returns an Operand with a new result ID in it. Increments the next_id_
diff --git a/src/tint/writer/spirv/builder_assign_test.cc b/src/tint/writer/spirv/builder_assign_test.cc
index a82d4b9..a6b8bc9 100644
--- a/src/tint/writer/spirv/builder_assign_test.cc
+++ b/src/tint/writer/spirv/builder_assign_test.cc
@@ -23,7 +23,7 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Assign_Var) {
-    auto* v = GlobalVar("var", ty.f32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* assign = Assign("var", 1_f);
 
@@ -51,7 +51,7 @@
 }
 
 TEST_F(BuilderTest, Assign_Var_OutsideFunction_IsError) {
-    auto* v = GlobalVar("var", ty.f32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* assign = Assign("var", Expr(1_f));
 
@@ -70,7 +70,7 @@
 }
 
 TEST_F(BuilderTest, Assign_Var_ZeroInitializer) {
-    auto* v = GlobalVar("var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* val = vec3<f32>();
     auto* assign = Assign("var", val);
@@ -101,7 +101,7 @@
 TEST_F(BuilderTest, Assign_Var_Complex_InitializerNestedVector) {
     auto* init = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
 
-    auto* v = GlobalVar("var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* assign = Assign("var", init);
 
@@ -134,7 +134,7 @@
 TEST_F(BuilderTest, Assign_Var_Complex_Initializer) {
     auto* init = vec3<f32>(1_f, 2_f, 3_f);
 
-    auto* v = GlobalVar("var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* assign = Assign("var", init);
 
@@ -209,7 +209,7 @@
 }
 
 TEST_F(BuilderTest, Assign_Vector) {
-    auto* v = GlobalVar("var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* val = vec3<f32>(1_f, 1_f, 3_f);
     auto* assign = Assign("var", val);
@@ -243,7 +243,7 @@
 TEST_F(BuilderTest, Assign_Vector_MemberByName) {
     // var.y = 1
 
-    auto* v = GlobalVar("var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* assign = Assign(MemberAccessor("var", "y"), Expr(1_f));
 
@@ -278,7 +278,7 @@
 TEST_F(BuilderTest, Assign_Vector_MemberByIndex) {
     // var[1] = 1
 
-    auto* v = GlobalVar("var", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* assign = Assign(IndexAccessor("var", 1_i), Expr(1_f));
 
diff --git a/src/tint/writer/spirv/builder_binary_expression_test.cc b/src/tint/writer/spirv/builder_binary_expression_test.cc
index b6dfb62..7251929 100644
--- a/src/tint/writer/spirv/builder_binary_expression_test.cc
+++ b/src/tint/writer/spirv/builder_binary_expression_test.cc
@@ -1031,8 +1031,8 @@
 }
 
 TEST_F(BuilderTest, Binary_LogicalAnd_WithLoads) {
-    auto* a_var = GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate, Expr(true));
-    auto* b_var = GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate, Expr(false));
+    auto* a_var = GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate, Expr(true));
+    auto* b_var = GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate, Expr(false));
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
 
     WrapInFunction(expr);
@@ -1207,8 +1207,8 @@
 }
 
 TEST_F(BuilderTest, Binary_LogicalOr_WithLoads) {
-    auto* a_var = GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate, Expr(true));
-    auto* b_var = GlobalVar("b", ty.bool_(), type::AddressSpace::kPrivate, Expr(false));
+    auto* a_var = GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate, Expr(true));
+    auto* b_var = GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate, Expr(false));
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
 
@@ -1251,19 +1251,19 @@
     switch (type) {
         case Type::f32:
             builder->GlobalVar(name, builder->ty.vec3<f32>(), builder->vec3<f32>(1_f, 1_f, 1_f),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
         case Type::f16:
             builder->GlobalVar(name, builder->ty.vec3<f16>(), builder->vec3<f16>(1_h, 1_h, 1_h),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
         case Type::i32:
             builder->GlobalVar(name, builder->ty.vec3<i32>(), builder->vec3<i32>(1_i, 1_i, 1_i),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
         case Type::u32:
             builder->GlobalVar(name, builder->ty.vec3<u32>(), builder->vec3<u32>(1_u, 1_u, 1_u),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
     }
     return builder->Expr(name);
@@ -1273,19 +1273,19 @@
     switch (type) {
         case Type::f32:
             builder->GlobalVar(name, builder->ty.f32(), builder->Expr(1_f),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
         case Type::f16:
             builder->GlobalVar(name, builder->ty.f16(), builder->Expr(1_h),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
         case Type::i32:
             builder->GlobalVar(name, builder->ty.i32(), builder->Expr(1_i),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
         case Type::u32:
             builder->GlobalVar(name, builder->ty.u32(), builder->Expr(1_u),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
     }
     return builder->Expr(name);
@@ -1580,11 +1580,11 @@
     switch (type) {
         case Type::f32:
             builder->GlobalVar(name, builder->ty.mat3x4<f32>(), builder->mat3x4<f32>(),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
         case Type::f16:
             builder->GlobalVar(name, builder->ty.mat3x4<f16>(), builder->mat3x4<f16>(),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
     }
     return builder->Expr(name);
@@ -1594,11 +1594,11 @@
     switch (type) {
         case Type::f32:
             builder->GlobalVar(name, builder->ty.mat4x3<f32>(), builder->mat4x3<f32>(),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
             break;
         case Type::f16:
             builder->GlobalVar(name, builder->ty.mat4x3<f16>(), builder->mat4x3<f16>(),
-                               type::AddressSpace::kPrivate);
+                               builtin::AddressSpace::kPrivate);
     }
     return builder->Expr(name);
 }
diff --git a/src/tint/writer/spirv/builder_builtin_test.cc b/src/tint/writer/spirv/builder_builtin_test.cc
index 693fdb1..1645ee6 100644
--- a/src/tint/writer/spirv/builder_builtin_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_test.cc
@@ -52,12 +52,12 @@
 
     Func("f1", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(expr1),
+             Decl(Let("l", expr1)),
          },
          utils::Empty);
     Func("f2", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(expr2),
+             Decl(Let("l", expr2)),
          },
          utils::Empty);
 
@@ -98,11 +98,11 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad_f32) {
-    auto* var = GlobalVar("ident", ty.f32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("ident", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("round", "ident");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -134,11 +134,11 @@
 TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("ident", ty.f16(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("ident", ty.f16(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("round", "ident");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -173,11 +173,11 @@
 using BuiltinBoolTest = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(BuiltinBoolTest, Call_Bool_Scalar) {
     auto param = GetParam();
-    auto* var = GlobalVar("v", ty.bool_(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.bool_(), builtin::AddressSpace::kPrivate);
     auto* expr = Call(param.name, "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -199,11 +199,11 @@
 
 TEST_P(BuiltinBoolTest, Call_Bool_Vector) {
     auto param = GetParam();
-    auto* var = GlobalVar("v", ty.vec3<bool>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.vec3<bool>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call(param.name, "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -232,13 +232,13 @@
                          testing::Values(BuiltinData{"any", "OpAny"}, BuiltinData{"all", "OpAll"}));
 
 TEST_F(BuiltinBuilderTest, Call_Select) {
-    auto* v3 = GlobalVar("v3", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* v3 = GlobalVar("v3", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    auto* bool_v3 = GlobalVar("bool_v3", ty.vec3<bool>(), type::AddressSpace::kPrivate);
+    auto* bool_v3 = GlobalVar("bool_v3", ty.vec3<bool>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("select", "v3", "v3", "bool_v3");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -278,13 +278,13 @@
     auto* s = Structure("my_struct", utils::Vector{
                                          Member("a", ty.array<f32>()),
                                      });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
     auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -322,13 +322,13 @@
                                          Member("z", ty.f32()),
                                          Member(4, "a", ty.array<f32>()),
                                      });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
     auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -365,7 +365,7 @@
     auto* s = Structure("my_struct", utils::Vector{
                                          Member("a", ty.array<f32>()),
                                      });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     auto* p = Let("p", AddressOf("b"));
@@ -376,7 +376,7 @@
          utils::Vector{
              Decl(p),
              Decl(p2),
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -424,7 +424,7 @@
     auto* s = Structure("my_struct", utils::Vector{
                                          Member("a", ty.array<f32>()),
                                      });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a),
               Group(2_a));
 
     auto* p = Let("p", AddressOf(Deref(AddressOf("b"))));
@@ -437,7 +437,7 @@
              Decl(p),
              Decl(p2),
              Decl(p3),
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -484,7 +484,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -525,7 +525,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -565,7 +565,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -609,7 +609,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -675,7 +675,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -712,7 +712,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -747,7 +747,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -786,7 +786,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -823,7 +823,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -862,7 +862,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -901,7 +901,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -942,7 +942,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -981,7 +981,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1024,7 +1024,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1072,7 +1072,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1112,7 +1112,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1150,7 +1150,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1188,7 +1188,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1224,7 +1224,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1264,7 +1264,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1302,7 +1302,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1342,7 +1342,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1382,7 +1382,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1424,7 +1424,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1464,7 +1464,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1508,7 +1508,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1557,7 +1557,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1598,7 +1598,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -1637,7 +1637,7 @@
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(vec),
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1691,7 +1691,7 @@
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(vec),
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1745,7 +1745,7 @@
     auto* expr = Call("modf", vec2<f32>(1_f, 2_f));
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1756,27 +1756,27 @@
     ASSERT_TRUE(b.Build()) << b.error();
     auto got = DumpBuilder(b);
     auto* expect = R"(OpCapability Shader
-%9 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %3 "a_func"
 OpExecutionMode %3 OriginUpperLeft
 OpName %3 "a_func"
-OpName %6 "__modf_result_vec2_f32"
-OpMemberName %6 0 "fract"
-OpMemberName %6 1 "whole"
-OpMemberDecorate %6 0 Offset 0
-OpMemberDecorate %6 1 Offset 8
+OpName %5 "__modf_result_vec2_f32"
+OpMemberName %5 0 "fract"
+OpMemberName %5 1 "whole"
+OpMemberDecorate %5 0 Offset 0
+OpMemberDecorate %5 1 Offset 8
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%8 = OpTypeFloat 32
-%7 = OpTypeVector %8 2
-%6 = OpTypeStruct %7 %7
-%10 = OpConstant %8 1
-%11 = OpConstant %8 2
-%12 = OpConstantComposite %7 %10 %11
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 2
+%5 = OpTypeStruct %6 %6
+%8 = OpConstantNull %6
+%9 = OpConstant %7 1
+%10 = OpConstant %7 2
+%11 = OpConstantComposite %6 %9 %10
+%12 = OpConstantComposite %5 %8 %11
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %9 ModfStruct %12
 OpReturn
 OpFunctionEnd
 )";
@@ -1791,7 +1791,7 @@
     auto* expr = Call("modf", vec2<f16>(1_h, 2_h));
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1806,27 +1806,27 @@
 OpCapability UniformAndStorageBuffer16BitAccess
 OpCapability StorageBuffer16BitAccess
 OpCapability StorageInputOutput16
-%9 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %3 "a_func"
 OpExecutionMode %3 OriginUpperLeft
 OpName %3 "a_func"
-OpName %6 "__modf_result_vec2_f16"
-OpMemberName %6 0 "fract"
-OpMemberName %6 1 "whole"
-OpMemberDecorate %6 0 Offset 0
-OpMemberDecorate %6 1 Offset 4
+OpName %5 "__modf_result_vec2_f16"
+OpMemberName %5 0 "fract"
+OpMemberName %5 1 "whole"
+OpMemberDecorate %5 0 Offset 0
+OpMemberDecorate %5 1 Offset 4
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%8 = OpTypeFloat 16
-%7 = OpTypeVector %8 2
-%6 = OpTypeStruct %7 %7
-%10 = OpConstant %8 0x1p+0
-%11 = OpConstant %8 0x1p+1
-%12 = OpConstantComposite %7 %10 %11
+%7 = OpTypeFloat 16
+%6 = OpTypeVector %7 2
+%5 = OpTypeStruct %6 %6
+%8 = OpConstantNull %6
+%9 = OpConstant %7 0x1p+0
+%10 = OpConstant %7 0x1p+1
+%11 = OpConstantComposite %6 %9 %10
+%12 = OpConstantComposite %5 %8 %11
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %9 ModfStruct %12
 OpReturn
 OpFunctionEnd
 )";
@@ -1841,7 +1841,7 @@
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(vec),
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1897,7 +1897,7 @@
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(vec),
-             CallStmt(expr),
+             Decl(Let("l", expr)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1952,7 +1952,7 @@
 TEST_F(BuiltinBuilderTest, Const_Call_Frexp_f32) {
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("frexp", vec2<f32>(1_f, 2_f))),
+             Decl(Let("l", Call("frexp", vec2<f32>(1_f, 2_f)))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1963,29 +1963,30 @@
     ASSERT_TRUE(b.Build()) << b.error();
     auto got = DumpBuilder(b);
     auto* expect = R"(OpCapability Shader
-%11 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %3 "a_func"
 OpExecutionMode %3 OriginUpperLeft
 OpName %3 "a_func"
-OpName %6 "__frexp_result_vec2_f32"
-OpMemberName %6 0 "fract"
-OpMemberName %6 1 "exp"
-OpMemberDecorate %6 0 Offset 0
-OpMemberDecorate %6 1 Offset 8
+OpName %5 "__frexp_result_vec2_f32"
+OpMemberName %5 0 "fract"
+OpMemberName %5 1 "exp"
+OpMemberDecorate %5 0 Offset 0
+OpMemberDecorate %5 1 Offset 8
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%8 = OpTypeFloat 32
-%7 = OpTypeVector %8 2
-%10 = OpTypeInt 32 1
-%9 = OpTypeVector %10 2
-%6 = OpTypeStruct %7 %9
-%12 = OpConstant %8 1
-%13 = OpConstant %8 2
-%14 = OpConstantComposite %7 %12 %13
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 2
+%9 = OpTypeInt 32 1
+%8 = OpTypeVector %9 2
+%5 = OpTypeStruct %6 %8
+%10 = OpConstant %7 0.5
+%11 = OpConstantComposite %6 %10 %10
+%12 = OpConstant %9 1
+%13 = OpConstant %9 2
+%14 = OpConstantComposite %8 %12 %13
+%15 = OpConstantComposite %5 %11 %14
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %11 FrexpStruct %14
 OpReturn
 OpFunctionEnd
 )";
@@ -1999,7 +2000,7 @@
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
-             CallStmt(Call("frexp", vec2<f16>(1_h, 2_h))),
+             Decl(Let("l", Call("frexp", vec2<f16>(1_h, 2_h)))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -2014,29 +2015,30 @@
 OpCapability UniformAndStorageBuffer16BitAccess
 OpCapability StorageBuffer16BitAccess
 OpCapability StorageInputOutput16
-%11 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %3 "a_func"
 OpExecutionMode %3 OriginUpperLeft
 OpName %3 "a_func"
-OpName %6 "__frexp_result_vec2_f16"
-OpMemberName %6 0 "fract"
-OpMemberName %6 1 "exp"
-OpMemberDecorate %6 0 Offset 0
-OpMemberDecorate %6 1 Offset 8
+OpName %5 "__frexp_result_vec2_f16"
+OpMemberName %5 0 "fract"
+OpMemberName %5 1 "exp"
+OpMemberDecorate %5 0 Offset 0
+OpMemberDecorate %5 1 Offset 8
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%8 = OpTypeFloat 16
-%7 = OpTypeVector %8 2
-%10 = OpTypeInt 32 1
-%9 = OpTypeVector %10 2
-%6 = OpTypeStruct %7 %9
-%12 = OpConstant %8 0x1p+0
-%13 = OpConstant %8 0x1p+1
-%14 = OpConstantComposite %7 %12 %13
+%7 = OpTypeFloat 16
+%6 = OpTypeVector %7 2
+%9 = OpTypeInt 32 1
+%8 = OpTypeVector %9 2
+%5 = OpTypeStruct %6 %8
+%10 = OpConstant %7 0x1p-1
+%11 = OpConstantComposite %6 %10 %10
+%12 = OpConstant %9 1
+%13 = OpConstant %9 2
+%14 = OpConstantComposite %8 %12 %13
+%15 = OpConstantComposite %5 %11 %14
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %11 FrexpStruct %14
 OpReturn
 OpFunctionEnd
 )";
@@ -2046,7 +2048,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_QuantizeToF16_Scalar) {
-    GlobalVar("v", Expr(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", Expr(2_f), builtin::AddressSpace::kPrivate);
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -2085,7 +2087,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_QuantizeToF16_Vector) {
-    GlobalVar("v", vec3<f32>(2_f), type::AddressSpace::kPrivate);
+    GlobalVar("v", vec3<f32>(2_f), builtin::AddressSpace::kPrivate);
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -2152,11 +2154,11 @@
 using BuiltinIntTest = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(BuiltinIntTest, Call_SInt_Scalar) {
     auto param = GetParam();
-    auto* var = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* expr = Call(param.name, "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2182,11 +2184,11 @@
 
 TEST_P(BuiltinIntTest, Call_SInt_Vector) {
     auto param = GetParam();
-    auto* var = GlobalVar("v", ty.vec3<i32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call(param.name, "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2213,11 +2215,11 @@
 
 TEST_P(BuiltinIntTest, Call_UInt_Scalar) {
     auto param = GetParam();
-    auto* var = GlobalVar("v", ty.u32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.u32(), builtin::AddressSpace::kPrivate);
     auto* expr = Call(param.name, "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2243,11 +2245,11 @@
 
 TEST_P(BuiltinIntTest, Call_UInt_Vector) {
     auto param = GetParam();
-    auto* var = GlobalVar("v", ty.vec3<u32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call(param.name, "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2284,7 +2286,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2322,7 +2324,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2366,7 +2368,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2399,7 +2401,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2436,7 +2438,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2475,7 +2477,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2520,7 +2522,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2559,7 +2561,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2604,7 +2606,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2644,7 +2646,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2690,7 +2692,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(scalar),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -2730,7 +2732,7 @@
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(vec),
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3114,11 +3116,11 @@
 namespace matrix_builtin_tests {
 
 TEST_F(BuiltinBuilderTest, Call_Determinant_f32) {
-    auto* var = GlobalVar("var", ty.mat3x3<f32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("var", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("determinant", "var");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3151,11 +3153,11 @@
 TEST_F(BuiltinBuilderTest, Call_Determinant_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("var", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("var", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("determinant", "var");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3186,11 +3188,11 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Transpose_f32) {
-    auto* var = GlobalVar("var", ty.mat2x3<f32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("var", ty.mat2x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("transpose", "var");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3224,11 +3226,11 @@
 TEST_F(BuiltinBuilderTest, Call_Transpose_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("var", ty.mat2x3<f16>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("var", ty.mat2x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("transpose", "var");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3265,11 +3267,11 @@
 namespace vector_builtin_tests {
 
 TEST_F(BuiltinBuilderTest, Call_Dot_F32) {
-    auto* var = GlobalVar("v", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("dot", "v", "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3296,11 +3298,11 @@
 TEST_F(BuiltinBuilderTest, Call_Dot_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("v", ty.vec3<f16>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("dot", "v", "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3325,11 +3327,11 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Dot_U32) {
-    auto* var = GlobalVar("v", ty.vec3<u32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("dot", "v", "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3364,11 +3366,11 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Dot_I32) {
-    auto* var = GlobalVar("v", ty.vec3<i32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call("dot", "v", "v");
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          Assign(Phony(), expr),
+                          Decl(Let("l", expr)),
                       });
 
     spirv::Builder& b = Build();
@@ -3410,11 +3412,11 @@
 using BuiltinDeriveTest = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(BuiltinDeriveTest, Call_Derivative_Scalar) {
     auto param = GetParam();
-    auto* var = GlobalVar("v", ty.f32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* expr = Call(param.name, "v");
     auto* func = Func("func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          CallStmt(expr),
+                          Decl(Let("l", expr)),
                       },
                       utils::Vector{
                           Stage(ast::PipelineStage::kFragment),
@@ -3443,11 +3445,11 @@
 
 TEST_P(BuiltinDeriveTest, Call_Derivative_Vector) {
     auto param = GetParam();
-    auto* var = GlobalVar("v", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
     auto* expr = Call(param.name, "v");
     auto* func = Func("func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          CallStmt(expr),
+                          Decl(Let("l", expr)),
                       },
                       utils::Vector{
                           Stage(ast::PipelineStage::kFragment),
@@ -3513,8 +3515,8 @@
                                  Member("u", ty.atomic<u32>()),
                                  Member("i", ty.atomic<i32>()),
                              });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Binding(1_a),
-              Group(2_a));
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Binding(1_a), Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -3577,8 +3579,8 @@
                                  Member("u", ty.atomic<u32>()),
                                  Member("i", ty.atomic<i32>()),
                              });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Binding(1_a),
-              Group(2_a));
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Binding(1_a), Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -3649,8 +3651,8 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("v", ty.atomic<i32>()),
                              });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Binding(1_a),
-              Group(2_a));
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Binding(1_a), Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -3722,8 +3724,8 @@
     auto* s = Structure("S", utils::Vector{
                                  Member("v", ty.atomic<u32>()),
                              });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Binding(1_a),
-              Group(2_a));
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Binding(1_a), Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -3797,8 +3799,8 @@
                                  Member("u", ty.atomic<u32>()),
                                  Member("i", ty.atomic<i32>()),
                              });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Binding(1_a),
-              Group(2_a));
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Binding(1_a), Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -3873,8 +3875,8 @@
                                  Member("u", ty.atomic<u32>()),
                                  Member("i", ty.atomic<i32>()),
                              });
-    GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite, Binding(1_a),
-              Group(2_a));
+    GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Binding(1_a), Group(2_a));
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -3942,11 +3944,11 @@
     auto param = GetParam();
 
     bool pack4 = param.name == "pack4x8snorm" || param.name == "pack4x8unorm";
-    auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 1_f, 1_f, 1_f))
-                       : Call(param.name, vec2<f32>(1_f, 1_f));
+    auto* call = pack4 ? Call(param.name, vec4<f32>("one")) : Call(param.name, vec2<f32>("one"));
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          CallStmt(call),
+                          Decl(Let("one", Expr(1_f))),
+                          Decl(Let("l", call)),
                       });
 
     spirv::Builder& b = Build();
@@ -3955,18 +3957,18 @@
 
     if (pack4) {
         auto got = DumpBuilder(b);
-        auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+        auto expect = R"(%9 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%6 = OpTypeInt 32 0
-%9 = OpTypeFloat 32
-%8 = OpTypeVector %9 4
-%10 = OpConstant %9 1
-%11 = OpConstantComposite %8 %10 %10 %10 %10
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypeInt 32 0
+%10 = OpTypeVector %5 4
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%11 = OpCompositeConstruct %10 %6 %6 %6 %6
+%7 = OpExtInst %8 %9 )" +
                       param.op +
                       R"( %11
 OpReturn
@@ -3975,18 +3977,18 @@
         EXPECT_EQ(got, expect);
     } else {
         auto got = DumpBuilder(b);
-        auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+        auto expect = R"(%9 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%6 = OpTypeInt 32 0
-%9 = OpTypeFloat 32
-%8 = OpTypeVector %9 2
-%10 = OpConstant %9 1
-%11 = OpConstantComposite %8 %10 %10
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypeInt 32 0
+%10 = OpTypeVector %5 2
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%11 = OpCompositeConstruct %10 %6 %6
+%7 = OpExtInst %8 %9 )" +
                       param.op +
                       R"( %11
 OpReturn
@@ -4016,7 +4018,8 @@
     bool pack4 = param.name == "unpack4x8snorm" || param.name == "unpack4x8unorm";
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
-                          CallStmt(Call(param.name, 1_u)),
+                          Decl(Let("one", Expr(1_u))),
+                          Decl(Let("l", Call(param.name, "one"))),
                       });
 
     spirv::Builder& b = Build();
@@ -4025,38 +4028,38 @@
 
     if (pack4) {
         auto got = DumpBuilder(b);
-        auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+        auto expect = R"(%10 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 4
-%9 = OpTypeInt 32 0
-%10 = OpConstant %9 1
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 4
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%7 = OpExtInst %8 %10 )" +
                       param.op +
-                      R"( %10
+                      R"( %6
 OpReturn
 OpFunctionEnd
 )";
         EXPECT_EQ(got, expect);
     } else {
         auto got = DumpBuilder(b);
-        auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+        auto expect = R"(%10 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%9 = OpTypeInt 32 0
-%10 = OpConstant %9 1
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%7 = OpExtInst %8 %10 )" +
                       param.op +
-                      R"( %10
+                      R"( %6
 OpReturn
 OpFunctionEnd
 )";
diff --git a/src/tint/writer/spirv/builder_builtin_texture_test.cc b/src/tint/writer/spirv/builder_builtin_texture_test.cc
index 793371b..4697582 100644
--- a/src/tint/writer/spirv/builder_builtin_texture_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_texture_test.cc
@@ -3717,7 +3717,8 @@
     auto* sampler = param.BuildSamplerVariable(this);
 
     auto* call = Call(param.function, param.args(this));
-    auto* stmt = CallStmt(call);
+    auto* stmt = param.returns_value ? static_cast<const ast::Statement*>(Assign(Phony(), call))
+                                     : static_cast<const ast::Statement*>(CallStmt(call));
     Func("func", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -3745,8 +3746,9 @@
     param.BuildSamplerVariable(this);
 
     auto* call = Call(param.function, param.args(this));
+    auto* stmt = param.returns_value ? static_cast<const ast::Statement*>(Assign(Phony(), call))
+                                     : static_cast<const ast::Statement*>(CallStmt(call));
 
-    auto* stmt = CallStmt(call);
     Func("main", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -3769,7 +3771,9 @@
     auto* sampler = param.BuildSamplerVariable(this);
 
     auto* call = Call(param.function, param.args(this));
-    auto* stmt = CallStmt(call);
+    auto* stmt = param.returns_value ? static_cast<const ast::Statement*>(Assign(Phony(), call))
+                                     : static_cast<const ast::Statement*>(CallStmt(call));
+
     Func("func", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
diff --git a/src/tint/writer/spirv/builder_initializer_expression_test.cc b/src/tint/writer/spirv/builder_constructor_expression_test.cc
similarity index 85%
rename from src/tint/writer/spirv/builder_initializer_expression_test.cc
rename to src/tint/writer/spirv/builder_constructor_expression_test.cc
index 9fdc4fc..29a47ac 100644
--- a/src/tint/writer/spirv/builder_initializer_expression_test.cc
+++ b/src/tint/writer/spirv/builder_constructor_expression_test.cc
@@ -20,15 +20,15 @@
 namespace tint::writer::spirv {
 namespace {
 
-using SpvBuilderInitializerTest = TestHelper;
+using SpvBuilderConstructorTest = TestHelper;
 
-TEST_F(SpvBuilderInitializerTest, Const) {
+TEST_F(SpvBuilderConstructorTest, Const) {
     auto* c = Expr(42.2_f);
-    auto* g = GlobalVar("g", ty.f32(), c, type::AddressSpace::kPrivate);
+    auto* g = GlobalVar("g", ty.f32(), c, builtin::AddressSpace::kPrivate);
 
     spirv::Builder& b = Build();
 
-    EXPECT_EQ(b.GenerateInitializerExpression(g, c), 2u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, c), 2u);
     ASSERT_FALSE(b.has_error()) << b.error();
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
@@ -36,13 +36,13 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type) {
+TEST_F(SpvBuilderConstructorTest, Type) {
     auto* t = vec3<f32>(1_f, 1_f, 3_f);
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
 
-    EXPECT_EQ(b.GenerateInitializerExpression(nullptr, t), 5u);
+    EXPECT_EQ(b.GenerateConstructorExpression(nullptr, t), 5u);
     ASSERT_FALSE(b.has_error()) << b.error();
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
@@ -53,7 +53,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_WithCasts) {
+TEST_F(SpvBuilderConstructorTest, Type_WithCasts) {
     auto* t = vec2<f32>(Call<f32>(1_i), Call<f32>(1_i));
     WrapInFunction(t);
 
@@ -72,7 +72,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_WithAlias) {
+TEST_F(SpvBuilderConstructorTest, Type_WithAlias) {
     // type Int = i32
     // cast<Int>(2.3f)
 
@@ -91,7 +91,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_IdentifierExpression_Param) {
+TEST_F(SpvBuilderConstructorTest, Type_IdentifierExpression_Param) {
     auto* var = Var("ident", ty.f32());
 
     auto* t = vec2<f32>(1_f, "ident");
@@ -121,7 +121,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Vector_Bitcast_Params) {
+TEST_F(SpvBuilderConstructorTest, Vector_Bitcast_Params) {
     auto* var = Var("v", vec3<f32>(1_f, 2_f, 3_f));
     auto* cast = Bitcast(ty.vec3<u32>(), var);
     WrapInFunction(var, cast);
@@ -150,7 +150,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Bool_With_Bool) {
+TEST_F(SpvBuilderConstructorTest, Type_Bool_With_Bool) {
     auto* cast = Call<bool>(true);
     WrapInFunction(cast);
 
@@ -167,7 +167,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_I32_With_I32) {
+TEST_F(SpvBuilderConstructorTest, Type_I32_With_I32) {
     auto* cast = Call<i32>(2_i);
     WrapInFunction(cast);
 
@@ -182,7 +182,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_U32_With_U32) {
+TEST_F(SpvBuilderConstructorTest, Type_U32_With_U32) {
     auto* cast = Call<u32>(2_u);
     WrapInFunction(cast);
 
@@ -197,7 +197,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_F32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_F32_With_F32) {
     auto* cast = Call<f32>(2_f);
     WrapInFunction(cast);
 
@@ -212,7 +212,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_F16_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_F16_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = Call<f16>(2_h);
@@ -229,7 +229,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_Bool_Literal) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool_Literal) {
     auto* cast = vec2<bool>(true);
     WrapInFunction(cast);
 
@@ -246,7 +246,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_Bool_Var) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool_Var) {
     auto* var = Var("v", Expr(true));
     auto* cast = vec2<bool>(var);
     WrapInFunction(var, cast);
@@ -270,7 +270,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F32_Literal) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_Literal) {
     auto* cast = vec2<f32>(2_f);
     WrapInFunction(cast);
 
@@ -287,7 +287,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F16_Literal) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_Literal) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(2_h);
@@ -306,7 +306,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F32_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
     auto* cast = vec2<f32>("x", "x");
     WrapInFunction(var, cast);
@@ -331,7 +331,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F16_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
@@ -358,7 +358,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F32_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32_Const) {
     auto* cast = vec2<f32>(1_f, 2_f);
     WrapInFunction(cast);
 
@@ -376,7 +376,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F16_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(1_h, 2_h);
@@ -396,7 +396,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_F32_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F32_With_Vec2) {
     auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
     auto* cast = vec2<f32>("x");
     WrapInFunction(var, cast);
@@ -421,7 +421,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_F16_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
@@ -448,7 +448,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_F32_With_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F32_With_Vec2_Const) {
     auto* cast = vec2<f32>(vec2<f32>(1_f, 2_f));
     WrapInFunction(cast);
 
@@ -466,7 +466,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec2_F16_With_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(vec2<f16>(1_h, 2_h));
@@ -486,7 +486,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
     auto* cast = vec3<f32>("x", "x", "x");
     WrapInFunction(var, cast);
@@ -512,7 +512,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
@@ -540,7 +540,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Const) {
     auto* cast = vec3<f32>(1_f, 2_f, 3_f);
     WrapInFunction(cast);
 
@@ -559,7 +559,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(1_h, 2_h, 3_h);
@@ -580,7 +580,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_Bool) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool) {
     auto* var = Decl(Var("x", ty.bool_(), Expr(true)));
     auto* cast = vec3<bool>("x", "x", "x");
     WrapInFunction(var, cast);
@@ -606,7 +606,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_Bool_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool_Const) {
     auto* cast = vec3<bool>(true, false, true);
     WrapInFunction(cast);
 
@@ -624,7 +624,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F32_F32_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
     auto* cast = vec3<f32>("x", "x", "x");
     WrapInFunction(var, cast);
@@ -650,7 +650,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_F16_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_F16_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
@@ -678,7 +678,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F32_F32_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32_Const) {
     auto* cast = vec3<f32>(1_f, 2_f, 3_f);
     WrapInFunction(cast);
 
@@ -697,7 +697,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_F16_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_F16_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(1_h, 2_h, 3_h);
@@ -718,7 +718,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2) {
     auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(2_f, 3_f)));
     auto* cast = vec3<f32>(1_f, "x");
     WrapInFunction(var, cast);
@@ -748,7 +748,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
@@ -780,7 +780,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F32_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2_Const) {
     auto* cast = vec3<f32>(1_f, vec2<f32>(2_f, 3_f));
     WrapInFunction(cast);
 
@@ -799,7 +799,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(1_h, vec2<f16>(2_h, 3_h));
@@ -820,7 +820,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_Vec2_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32) {
     auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
     auto* cast = vec3<f32>("x", 3_f);
     WrapInFunction(var, cast);
@@ -850,7 +850,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_Vec2_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
@@ -882,7 +882,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_Vec2_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32_Const) {
     auto* cast = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
     WrapInFunction(cast);
 
@@ -901,7 +901,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_Vec2_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec2<f16>(1_h, 2_h), 3_h);
@@ -922,7 +922,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_F32_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F32_With_Vec3) {
     auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(1_f, 2_f, 3_f)));
     auto* cast = vec3<f32>("x");
     WrapInFunction(var, cast);
@@ -948,7 +948,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_F16_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(1_h, 2_h, 3_h)));
@@ -976,7 +976,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_F32_With_Vec3_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F32_With_Vec3_Const) {
     auto* cast = vec3<f32>(vec3<f32>(1_f, 2_f, 3_f));
     WrapInFunction(cast);
 
@@ -995,7 +995,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec3_F16_With_Vec3_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec3<f16>(1_h, 2_h, 3_h));
@@ -1016,7 +1016,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Bool) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Bool) {
     auto* var = Decl(Var("x", ty.bool_(), Expr(true)));
     auto* cast = vec4<bool>("x");
     WrapInFunction(var, cast);
@@ -1040,7 +1040,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Bool_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Bool_Const) {
     auto* cast = vec4<bool>(true);
     WrapInFunction(cast);
 
@@ -1057,7 +1057,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
     auto* cast = vec4<f32>("x");
     WrapInFunction(var, cast);
@@ -1081,7 +1081,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
@@ -1107,7 +1107,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Const) {
     auto* cast = vec4<f32>(2_f);
     WrapInFunction(cast);
 
@@ -1124,7 +1124,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h);
@@ -1143,7 +1143,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_F32_F32_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
     auto* cast = vec4<f32>("x", "x", "x", "x");
     WrapInFunction(var, cast);
@@ -1170,7 +1170,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_F16_F16_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_F16_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
@@ -1199,7 +1199,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_F32_F32_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32_Const) {
     auto* cast = vec4<f32>(1_f, 2_f, 3_f, 4_f);
     WrapInFunction(cast);
 
@@ -1219,7 +1219,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_F16_F16_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_F16_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(1_h, 2_h, 3_h, 4_h);
@@ -1241,7 +1241,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2) {
     auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
     auto* cast = vec4<f32>(1_f, 2_f, "x");
     WrapInFunction(var, cast);
@@ -1270,7 +1270,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_F16_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
@@ -1301,7 +1301,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_F32_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2_Const) {
     auto* cast = vec4<f32>(1_f, 2_f, vec2<f32>(3_f, 4_f));
     WrapInFunction(cast);
 
@@ -1321,7 +1321,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_F16_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(1_h, 2_h, vec2<f16>(3_h, 4_h));
@@ -1343,7 +1343,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_Vec2_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32) {
     auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(2_f, 3_f)));
     auto* cast = vec4<f32>(1_f, "x", 4_f);
     WrapInFunction(var, cast);
@@ -1374,7 +1374,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Vec2_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
@@ -1407,7 +1407,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_Vec2_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32_Const) {
     auto* cast = vec4<f32>(1_f, vec2<f32>(2_f, 3_f), 4_f);
     WrapInFunction(cast);
 
@@ -1427,7 +1427,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Vec2_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(1_h, vec2<f16>(2_h, 3_h), 4_h);
@@ -1449,7 +1449,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec2_F32_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32) {
     auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
     auto* cast = vec4<f32>("x", 3_f, 4_f);
     WrapInFunction(var, cast);
@@ -1480,7 +1480,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec2_F16_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
@@ -1513,7 +1513,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec2_F32_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32_Const) {
     auto* cast = vec4<f32>(vec2<f32>(1_f, 2_f), 3_f, 4_f);
     WrapInFunction(cast);
 
@@ -1533,7 +1533,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec2_F16_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), 3_h, 4_h);
@@ -1555,7 +1555,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_F32_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec2_Vec2) {
     auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
     auto* cast = vec4<f32>("x", "x");
     WrapInFunction(var, cast);
@@ -1587,7 +1587,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_F16_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
@@ -1621,7 +1621,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_F32_With_Vec2_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec2_Vec2_Const) {
     auto* cast = vec4<f32>(vec2<f32>(1_f, 2_f), vec2<f32>(1_f, 2_f));
     WrapInFunction(cast);
 
@@ -1639,7 +1639,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_F16_With_Vec2_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec2_Vec2_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), vec2<f16>(1_h, 2_h));
@@ -1659,7 +1659,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3) {
     auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(2_f, 2_f, 2_f)));
     auto* cast = vec4<f32>(2_f, "x");
     WrapInFunction(var, cast);
@@ -1688,7 +1688,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
@@ -1719,7 +1719,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F32_Vec3_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3_Const) {
     auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
@@ -1736,7 +1736,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Vec3_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
@@ -1755,7 +1755,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec3_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32) {
     auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(2_f, 2_f, 2_f)));
     auto* cast = vec4<f32>("x", 2_f);
     WrapInFunction(var, cast);
@@ -1784,7 +1784,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec3_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
@@ -1815,7 +1815,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec3_F32_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32_Const) {
     auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
     WrapInFunction(cast);
 
@@ -1832,7 +1832,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec3_F16_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16_Const) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
@@ -1851,7 +1851,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_F32_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec4) {
     auto* value = vec4<f32>(2_f, 2_f, 2_f, 2_f);
     auto* cast = vec4<f32>(value);
     WrapInFunction(cast);
@@ -1869,7 +1869,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Vec4_F16_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec4) {
     Enable(builtin::Extension::kF16);
 
     auto* value = vec4<f16>(2_h, 2_h, 2_h, 2_h);
@@ -1889,7 +1889,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_F32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F32_With_F32) {
     auto* ctor = Call<f32>(2_f);
     GlobalConst("g", ty.f32(), ctor);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -1910,7 +1910,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_F16_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F16_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* ctor = Call<f16>(2_h);
@@ -1933,9 +1933,9 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_F32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F32_With_F32) {
     auto* ctor = Call<f32>(2_f);
-    GlobalVar("g", ty.f32(), type::AddressSpace::kPrivate, ctor);
+    GlobalVar("g", ty.f32(), builtin::AddressSpace::kPrivate, ctor);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -1950,11 +1950,11 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_F16_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F16_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* ctor = Call<f16>(2_h);
-    GlobalVar("g", ty.f16(), type::AddressSpace::kPrivate, ctor);
+    GlobalVar("g", ty.f16(), builtin::AddressSpace::kPrivate, ctor);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -1969,7 +1969,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_U32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F32) {
     auto* ctor = Call<u32>(1.5_f);
     GlobalConst("g", ty.u32(), ctor);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -1990,7 +1990,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_U32_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* ctor = Call<u32>(1.5_h);
@@ -2013,9 +2013,9 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_U32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F32) {
     auto* ctor = Call<u32>(1.5_f);
-    GlobalVar("g", ty.u32(), type::AddressSpace::kPrivate, ctor);
+    GlobalVar("g", ty.u32(), builtin::AddressSpace::kPrivate, ctor);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -2030,11 +2030,11 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_U32_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* ctor = Call<u32>(1.5_h);
-    GlobalVar("g", ty.u32(), type::AddressSpace::kPrivate, ctor);
+    GlobalVar("g", ty.u32(), builtin::AddressSpace::kPrivate, ctor);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -2049,7 +2049,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec2_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F32) {
     auto* cast = vec2<f32>(2_f);
     GlobalConst("g", ty.vec2<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2072,7 +2072,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec2_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(2_h);
@@ -2097,14 +2097,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec2_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F32) {
     auto* cast = vec2<f32>(2_f);
-    auto* g = GlobalVar("g", ty.vec2<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec2<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
@@ -2113,16 +2113,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec2_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(2_h);
-    auto* g = GlobalVar("g", ty.vec2<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec2<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 2
@@ -2131,7 +2131,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec2_F32_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_F32_With_Vec2) {
     auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
     GlobalConst("g", ty.vec2<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2154,7 +2154,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec2_F16_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_F16_With_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
@@ -2179,9 +2179,9 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec2_F32_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_F32_With_Vec2) {
     auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
-    GlobalVar("a", ty.vec2<f32>(), type::AddressSpace::kPrivate, cast);
+    GlobalVar("a", ty.vec2<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -2199,11 +2199,11 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec2_F16_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_F16_With_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
-    GlobalVar("a", ty.vec2<f16>(), type::AddressSpace::kPrivate, cast);
+    GlobalVar("a", ty.vec2<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -2221,7 +2221,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_F32_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_F32_With_Vec3) {
     auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec3<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2244,7 +2244,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_F16_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_F16_With_Vec3) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
@@ -2269,9 +2269,9 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_F32_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_F32_With_Vec3) {
     auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
-    GlobalVar("a", ty.vec3<f32>(), type::AddressSpace::kPrivate, cast);
+    GlobalVar("a", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -2289,11 +2289,11 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_F16_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_F16_With_Vec3) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
-    GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate, cast);
+    GlobalVar("a", ty.vec3<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -2311,7 +2311,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_F32_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F32_With_Vec4) {
     auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2334,7 +2334,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_F16_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F16_With_Vec4) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
@@ -2359,9 +2359,9 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_F32_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F32_With_Vec4) {
     auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
-    GlobalVar("a", ty.vec4<f32>(), type::AddressSpace::kPrivate, cast);
+    GlobalVar("a", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -2379,11 +2379,11 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_F16_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec4) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
-    GlobalVar("a", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
+    GlobalVar("a", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -2401,7 +2401,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32) {
     auto* cast = vec3<f32>(2_f);
     GlobalConst("g", ty.vec3<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2424,7 +2424,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(2_h);
@@ -2449,14 +2449,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32) {
     auto* cast = vec3<f32>(2_f);
-    auto* g = GlobalVar("g", ty.vec3<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
@@ -2465,16 +2465,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(2_h);
-    auto* g = GlobalVar("g", ty.vec3<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec3<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 3
@@ -2483,7 +2483,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32_Vec2) {
     auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
     GlobalConst("g", ty.vec3<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2506,7 +2506,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_F16_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
@@ -2531,14 +2531,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32_Vec2) {
     auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
-    auto* g = GlobalVar("g", ty.vec3<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
@@ -2547,16 +2547,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_F16_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
-    auto* g = GlobalVar("g", ty.vec3<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec3<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 3
@@ -2565,7 +2565,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_Vec2_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F32) {
     auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec3<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2588,7 +2588,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_Vec2_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
@@ -2613,14 +2613,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_Vec2_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F32) {
     auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
-    auto* g = GlobalVar("g", ty.vec3<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
@@ -2629,16 +2629,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_Vec2_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
-    auto* g = GlobalVar("g", ty.vec3<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec3<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 3
@@ -2647,7 +2647,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32) {
     auto* cast = vec4<f32>(2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2670,7 +2670,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h);
@@ -2695,14 +2695,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32) {
     auto* cast = vec4<f32>(2_f);
-    auto* g = GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
@@ -2711,16 +2711,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h);
-    auto* g = GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 4
@@ -2729,7 +2729,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F32_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_F32_Vec2) {
     auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2752,7 +2752,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F16_F16_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
@@ -2777,14 +2777,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F32_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_F32_Vec2) {
     auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
-    auto* g = GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
@@ -2793,16 +2793,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F16_F16_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
-    auto* g = GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 4
@@ -2811,7 +2811,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F32_Vec2_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec2_F32) {
     auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2834,7 +2834,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F16_Vec2_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
@@ -2859,14 +2859,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F32_Vec2_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec2_F32) {
     auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
-    auto* g = GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
@@ -2875,16 +2875,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F16_Vec2_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
-    auto* g = GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 4
@@ -2893,7 +2893,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_Vec2_F32_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F32_F32) {
     auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2916,7 +2916,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_Vec2_F16_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F16_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
@@ -2941,14 +2941,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_Vec2_F32_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F32_F32) {
     auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
-    auto* g = GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
@@ -2957,16 +2957,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_Vec2_F16_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F16_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
-    auto* g = GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 4
@@ -2975,7 +2975,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_F32_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F32_With_Vec2_Vec2) {
     auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -2998,7 +2998,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_F16_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F16_With_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
@@ -3023,14 +3023,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_F32_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F32_With_Vec2_Vec2) {
     auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
-    auto* g = GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
@@ -3039,16 +3039,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_F16_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
-    auto* g = GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 4
@@ -3057,7 +3057,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F32_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec3) {
     auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -3080,14 +3080,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F32_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec3) {
     auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
-    auto* g = GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
@@ -3096,16 +3096,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F16_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec3) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
-    auto* g = GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 4
@@ -3114,7 +3114,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_Vec3_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F32) {
     auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
@@ -3137,7 +3137,7 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_Vec3_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
@@ -3162,14 +3162,14 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_Vec3_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F32) {
     auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
-    auto* g = GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
@@ -3178,16 +3178,16 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_Vec3_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
-    auto* g = GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
+    auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateInitializerExpression(g, cast), 4u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
 %1 = OpTypeVector %2 4
@@ -3196,7 +3196,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat2x2_F32_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_F32_With_Vec2_Vec2) {
     auto* cast = mat2x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
     WrapInFunction(cast);
 
@@ -3214,7 +3214,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat2x2_F16_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_F16_With_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = mat2x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
@@ -3234,7 +3234,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat3x2_F32_With_Vec2_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_F32_With_Vec2_Vec2_Vec2) {
     auto* cast = mat3x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
     WrapInFunction(cast);
 
@@ -3252,7 +3252,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat3x2_F16_With_Vec2_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_F16_With_Vec2_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = mat3x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
@@ -3272,7 +3272,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat4x2_F32_With_Vec2_Vec2_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_F32_With_Vec2_Vec2_Vec2_Vec2) {
     auto* cast = mat4x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f),
                              vec2<f32>(2_f, 2_f));
     WrapInFunction(cast);
@@ -3291,7 +3291,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat4x2_F16_With_Vec2_Vec2_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_F16_With_Vec2_Vec2_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = mat4x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h),
@@ -3312,7 +3312,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat2x3_F32_With_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_F32_With_Vec3_Vec3) {
     auto* cast = mat2x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
@@ -3330,7 +3330,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat2x3_F16_With_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_F16_With_Vec3_Vec3) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = mat2x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
@@ -3350,7 +3350,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat3x3_F32_With_Vec3_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_F32_With_Vec3_Vec3_Vec3) {
     auto* cast =
         mat3x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
     WrapInFunction(cast);
@@ -3369,7 +3369,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat3x3_F16_With_Vec3_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_F16_With_Vec3_Vec3_Vec3) {
     Enable(builtin::Extension::kF16);
 
     auto* cast =
@@ -3390,7 +3390,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat4x3_F32_With_Vec3_Vec3_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_F32_With_Vec3_Vec3_Vec3_Vec3) {
     auto* cast = mat4x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f),
                              vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
     WrapInFunction(cast);
@@ -3409,7 +3409,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat4x3_F16_With_Vec3_Vec3_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_F16_With_Vec3_Vec3_Vec3_Vec3) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = mat4x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h),
@@ -3430,7 +3430,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat2x4_F32_With_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_F32_With_Vec4_Vec4) {
     auto* cast = mat2x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
@@ -3448,7 +3448,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat2x4_F16_With_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_F16_With_Vec4_Vec4) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = mat2x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h));
@@ -3468,7 +3468,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat3x4_F32_With_Vec4_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_F32_With_Vec4_Vec4_Vec4) {
     auto* cast = mat3x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f),
                              vec4<f32>(2_f, 2_f, 2_f, 2_f));
     WrapInFunction(cast);
@@ -3487,7 +3487,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat3x4_F16_With_Vec4_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_F16_With_Vec4_Vec4_Vec4) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = mat3x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h),
@@ -3508,7 +3508,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat4x4_F32_With_Vec4_Vec4_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F32_With_Vec4_Vec4_Vec4_Vec4) {
     auto* cast = mat4x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f),
                              vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f));
     WrapInFunction(cast);
@@ -3527,7 +3527,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Mat4x4_F16_With_Vec4_Vec4_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F16_With_Vec4_Vec4_Vec4_Vec4) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = mat4x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h),
@@ -3548,7 +3548,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Array_5_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Array_5_F32) {
     auto* cast = array<f32, 5>(2_f, 2_f, 2_f, 2_f, 2_f);
     WrapInFunction(cast);
 
@@ -3566,7 +3566,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Array_5_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Array_5_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* cast = array<f16, 5>(2_h, 2_h, 2_h, 2_h, 2_h);
@@ -3586,7 +3586,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Array_2_Vec3_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F32) {
     auto* first = vec3<f32>(1_f, 2_f, 3_f);
     auto* second = vec3<f32>(1_f, 2_f, 3_f);
     auto* t = Call(ty.array(ty.vec3<f32>(), 2_u), first, second);
@@ -3608,7 +3608,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Array_2_Vec3_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* first = vec3<f16>(1_h, 2_h, 3_h);
@@ -3632,7 +3632,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, CommonInitializer_TwoVectors) {
+TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoVectors) {
     auto* v1 = vec3<f32>(2_f, 2_f, 2_f);
     auto* v2 = vec3<f32>(2_f, 2_f, 2_f);
     WrapInFunction(WrapInStatement(v1), WrapInStatement(v2));
@@ -3650,7 +3650,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, CommonInitializer_TwoArrays) {
+TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoArrays) {
     auto* a1 = array<f32, 3>(2_f, 2_f, 2_f);
     auto* a2 = array<f32, 3>(2_f, 2_f, 2_f);
     WrapInFunction(WrapInStatement(a1), WrapInStatement(a2));
@@ -3670,7 +3670,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, CommonInitializer_Array_VecArray) {
+TEST_F(SpvBuilderConstructorTest, CommonInitializer_Array_VecArray) {
     // Test that initializers of different types with the same values produce
     // different OpConstantComposite instructions.
     // crbug.com/tint/777
@@ -3695,7 +3695,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Struct) {
+TEST_F(SpvBuilderConstructorTest, Type_Struct) {
     auto* s = Structure("my_struct", utils::Vector{
                                          Member("a", ty.f32()),
                                          Member("b", ty.vec3<f32>()),
@@ -3720,7 +3720,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_F32) {
     auto* t = Call<f32>();
 
     WrapInFunction(t);
@@ -3737,7 +3737,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* t = Call<f16>();
@@ -3756,7 +3756,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_I32) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_I32) {
     auto* t = Call<i32>();
 
     WrapInFunction(t);
@@ -3773,7 +3773,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_U32) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_U32) {
     auto* t = Call<u32>();
 
     WrapInFunction(t);
@@ -3790,7 +3790,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_Bool) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Bool) {
     auto* t = Call<bool>();
 
     WrapInFunction(t);
@@ -3807,7 +3807,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_Vector) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Vector) {
     auto* t = vec2<i32>();
 
     WrapInFunction(t);
@@ -3825,7 +3825,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_Matrix_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F32) {
     auto* t = mat4x2<f32>();
 
     WrapInFunction(t);
@@ -3844,7 +3844,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_Matrix_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* t = mat4x2<f16>();
@@ -3865,7 +3865,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_Array) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
     auto* t = array<i32, 2>();
 
     WrapInFunction(t);
@@ -3885,7 +3885,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_Struct) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Struct) {
     auto* s = Structure("my_struct", utils::Vector{Member("a", ty.f32())});
     auto* t = Call(ty.Of(s));
     WrapInFunction(t);
@@ -3903,7 +3903,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_U32_To_I32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_I32) {
     auto* var = Decl(Var("x", ty.u32(), Expr(2_u)));
     auto* cast = Call<i32>("x");
     WrapInFunction(var, cast);
@@ -3927,7 +3927,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_F32_To_I32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_I32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2.4_f)));
     auto* cast = Call<i32>("x");
     WrapInFunction(var, cast);
@@ -3951,7 +3951,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_F16_To_I32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F16_To_I32) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2.4_h)));
@@ -3977,7 +3977,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_I32_To_U32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_U32) {
     auto* var = Decl(Var("x", ty.i32(), Expr(2_i)));
     auto* cast = Call<u32>("x");
     WrapInFunction(var, cast);
@@ -4001,7 +4001,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_F32_To_U32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_U32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2.4_f)));
     auto* cast = Call<u32>("x");
     WrapInFunction(var, cast);
@@ -4025,7 +4025,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_F16_To_U32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F16_To_U32) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2.4_h)));
@@ -4051,7 +4051,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_I32_To_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F32) {
     auto* var = Decl(Var("x", ty.i32(), Expr(2_i)));
     auto* cast = Call<f32>("x");
     WrapInFunction(var, cast);
@@ -4075,7 +4075,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_U32_To_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F32) {
     auto* var = Decl(Var("x", ty.u32(), Expr(2_u)));
     auto* cast = Call<f32>("x");
     WrapInFunction(var, cast);
@@ -4099,7 +4099,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_F16_To_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F16_To_F32) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
@@ -4125,7 +4125,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_I32_To_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.i32(), Expr(2_i)));
@@ -4151,7 +4151,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_U32_To_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.u32(), Expr(2_u)));
@@ -4177,7 +4177,7 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_F32_To_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_F16) {
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
@@ -4203,8 +4203,8 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_U32_to_I32) {
-    auto* var = GlobalVar("i", ty.vec3<u32>(), type::AddressSpace::kPrivate);
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_I32) {
+    auto* var = GlobalVar("i", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<i32>("i");
     WrapInFunction(cast);
@@ -4229,8 +4229,8 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F32_to_I32) {
-    auto* var = GlobalVar("i", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_I32) {
+    auto* var = GlobalVar("i", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<i32>("i");
     WrapInFunction(cast);
@@ -4255,10 +4255,10 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F16_to_I32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_I32) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("i", ty.vec3<f16>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("i", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<i32>("i");
     WrapInFunction(cast);
@@ -4283,8 +4283,8 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_I32_to_U32) {
-    auto* var = GlobalVar("i", ty.vec3<i32>(), type::AddressSpace::kPrivate);
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_U32) {
+    auto* var = GlobalVar("i", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<u32>("i");
     WrapInFunction(cast);
@@ -4309,8 +4309,8 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F32_to_U32) {
-    auto* var = GlobalVar("i", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_U32) {
+    auto* var = GlobalVar("i", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<u32>("i");
     WrapInFunction(cast);
@@ -4335,10 +4335,10 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F16_to_U32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_U32) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("i", ty.vec3<f16>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("i", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<u32>("i");
     WrapInFunction(cast);
@@ -4363,8 +4363,8 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_I32_to_F32) {
-    auto* var = GlobalVar("i", ty.vec3<i32>(), type::AddressSpace::kPrivate);
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F32) {
+    auto* var = GlobalVar("i", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<f32>("i");
     WrapInFunction(cast);
@@ -4389,8 +4389,8 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_U32_to_F32) {
-    auto* var = GlobalVar("i", ty.vec3<u32>(), type::AddressSpace::kPrivate);
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F32) {
+    auto* var = GlobalVar("i", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<f32>("i");
     WrapInFunction(cast);
@@ -4415,10 +4415,10 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F16_to_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_F32) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("i", ty.vec3<f16>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("i", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<f32>("i");
     WrapInFunction(cast);
@@ -4443,10 +4443,10 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_I32_to_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("i", ty.vec3<i32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("i", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<f16>("i");
     WrapInFunction(cast);
@@ -4471,10 +4471,10 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_U32_to_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("i", ty.vec3<u32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("i", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<f16>("i");
     WrapInFunction(cast);
@@ -4499,10 +4499,10 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F32_to_F16) {
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalVar("i", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("i", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* cast = vec3<f16>("i");
     WrapInFunction(cast);
@@ -4527,18 +4527,18 @@
 )");
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_GlobalVectorWithAllConstInitializers) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithAllConstInitializers) {
     // vec3<f32>(1.0, 2.0, 3.0)  -> true
     auto* t = vec3<f32>(1_f, 2_f, 3_f);
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
 
-    EXPECT_TRUE(b.IsInitializerConst(t));
+    EXPECT_TRUE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_GlobalArrayWithAllConstInitializers) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalArrayWithAllConstInitializers) {
     // array<vec3<f32>, 2u>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(1.0, 2.0, 3.0))
     //   -> true
     auto* t =
@@ -4547,11 +4547,11 @@
 
     spirv::Builder& b = Build();
 
-    EXPECT_TRUE(b.IsInitializerConst(t));
+    EXPECT_TRUE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_GlobalVectorWithMatchingTypeInitializers) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithMatchingTypeInitializers) {
     // vec2<f32>(f32(1.0), f32(2.0))  -> false
 
     auto* t = vec2<f32>(Call<f32>(1_f), Call<f32>(2_f));
@@ -4559,11 +4559,11 @@
 
     spirv::Builder& b = Build();
 
-    EXPECT_TRUE(b.IsInitializerConst(t));
+    EXPECT_TRUE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_GlobalWithTypeConversionInitializer) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalWithTypeConversionInitializer) {
     // vec2<f32>(f32(1), f32(2)) -> false
 
     auto* t = vec2<f32>(Call<f32>(1_i), Call<f32>(2_i));
@@ -4571,11 +4571,11 @@
 
     spirv::Builder& b = Build();
 
-    EXPECT_FALSE(b.IsInitializerConst(t));
+    EXPECT_FALSE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_VectorWithAllConstInitializers) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_VectorWithAllConstInitializers) {
     // vec3<f32>(1.0, 2.0, 3.0)  -> true
 
     auto* t = vec3<f32>(1_f, 2_f, 3_f);
@@ -4583,27 +4583,27 @@
 
     spirv::Builder& b = Build();
 
-    EXPECT_TRUE(b.IsInitializerConst(t));
+    EXPECT_TRUE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_Vector_WithIdent) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Vector_WithIdent) {
     // vec3<f32>(a, b, c)  -> false
 
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("c", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("c", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* t = vec3<f32>("a", "b", "c");
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
 
-    EXPECT_FALSE(b.IsInitializerConst(t));
+    EXPECT_FALSE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_ArrayWithAllConstInitializers) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_ArrayWithAllConstInitializers) {
     // array<vec3<f32>, 2u>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(1.0, 2.0, 3.0))
     //   -> true
 
@@ -4615,11 +4615,11 @@
 
     spirv::Builder& b = Build();
 
-    EXPECT_TRUE(b.IsInitializerConst(t));
+    EXPECT_TRUE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_VectorWithTypeConversionConstInitializers) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_VectorWithTypeConversionConstInitializers) {
     // vec2<f32>(f32(1), f32(2))  -> false
 
     auto* t = vec2<f32>(Call<f32>(1_i), Call<f32>(2_i));
@@ -4627,21 +4627,21 @@
 
     spirv::Builder& b = Build();
 
-    EXPECT_FALSE(b.IsInitializerConst(t));
+    EXPECT_FALSE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_BitCastScalars) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_BitCastScalars) {
     auto* t = vec2<u32>(Call<u32>(1_i), Call<u32>(1_i));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
 
-    EXPECT_FALSE(b.IsInitializerConst(t));
+    EXPECT_FALSE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_Struct) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
     auto* s = Structure("my_struct", utils::Vector{
                                          Member("a", ty.f32()),
                                          Member("b", ty.vec3<f32>()),
@@ -4652,29 +4652,29 @@
 
     spirv::Builder& b = Build();
 
-    EXPECT_TRUE(b.IsInitializerConst(t));
+    EXPECT_TRUE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, IsInitializerConst_Struct_WithIdentSubExpression) {
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct_WithIdentSubExpression) {
     auto* s = Structure("my_struct", utils::Vector{
                                          Member("a", ty.f32()),
                                          Member("b", ty.vec3<f32>()),
                                      });
 
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("b", ty.vec3<f32>(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
     auto* t = Call(ty.Of(s), "a", "b");
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
 
-    EXPECT_FALSE(b.IsInitializerConst(t));
+    EXPECT_FALSE(b.IsConstructorConst(t));
     EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderInitializerTest, ConstantCompositeScoping) {
+TEST_F(SpvBuilderConstructorTest, ConstantCompositeScoping) {
     // if (true) {
     //    let x = vec3<f32>(1.0, 2.0, 3.0);
     // }
@@ -4715,9 +4715,9 @@
 }
 
 // TODO(crbug.com/tint/1155) Implement when overrides are fully implemented.
-// TEST_F(SpvBuilderInitializerTest, SpecConstantCompositeScoping)
+// TEST_F(SpvBuilderConstructorTest, SpecConstantCompositeScoping)
 
-TEST_F(SpvBuilderInitializerTest, CompositeConstructScoping) {
+TEST_F(SpvBuilderConstructorTest, CompositeConstructScoping) {
     // var one = 1.0;
     // if (true) {
     //    let x = vec3<f32>(one, 2.0, 3.0);
diff --git a/src/tint/writer/spirv/builder_entry_point_test.cc b/src/tint/writer/spirv/builder_entry_point_test.cc
index 59e1848..085a6f2 100644
--- a/src/tint/writer/spirv/builder_entry_point_test.cc
+++ b/src/tint/writer/spirv/builder_entry_point_test.cc
@@ -20,9 +20,9 @@
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/variable.h"
+#include "src/tint/builtin/address_space.h"
 #include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program.h"
-#include "src/tint/type/address_space.h"
 #include "src/tint/type/f32.h"
 #include "src/tint/type/vector.h"
 #include "src/tint/writer/spirv/builder.h"
diff --git a/src/tint/writer/spirv/builder_format_conversion_test.cc b/src/tint/writer/spirv/builder_format_conversion_test.cc
index cd1322f..63f2183 100644
--- a/src/tint/writer/spirv/builder_format_conversion_test.cc
+++ b/src/tint/writer/spirv/builder_format_conversion_test.cc
@@ -19,7 +19,7 @@
 namespace {
 
 struct TestData {
-    type::TexelFormat ast_format;
+    builtin::TexelFormat ast_format;
     SpvImageFormat_ spv_format;
     bool extended_format = false;
 };
@@ -45,46 +45,47 @@
     }
 }
 
-INSTANTIATE_TEST_SUITE_P(BuilderTest,
-                         ImageFormatConversionTest,
-                         testing::Values(
-                             /* WGSL unsupported formats
-                       TestData{type::TexelFormat::kR8Unorm, SpvImageFormatR8, true},
-                       TestData{type::TexelFormat::kR8Snorm, SpvImageFormatR8Snorm, true},
-                       TestData{type::TexelFormat::kR8Uint, SpvImageFormatR8ui, true},
-                       TestData{type::TexelFormat::kR8Sint, SpvImageFormatR8i, true},
-                       TestData{type::TexelFormat::kR16Uint, SpvImageFormatR16ui, true},
-                       TestData{type::TexelFormat::kR16Sint, SpvImageFormatR16i, true},
-                       TestData{type::TexelFormat::kR16Float, SpvImageFormatR16f, true},
-                       TestData{type::TexelFormat::kRg8Unorm, SpvImageFormatRg8, true},
-                       TestData{type::TexelFormat::kRg8Snorm, SpvImageFormatRg8Snorm, true},
-                       TestData{type::TexelFormat::kRg8Uint, SpvImageFormatRg8ui, true},
-                       TestData{type::TexelFormat::kRg8Sint, SpvImageFormatRg8i, true},
-                       TestData{type::TexelFormat::kRg16Uint, SpvImageFormatRg16ui, true},
-                       TestData{type::TexelFormat::kRg16Sint, SpvImageFormatRg16i, true},
-                       TestData{type::TexelFormat::kRg16Float, SpvImageFormatRg16f, true},
-                       TestData{type::TexelFormat::kRgba8UnormSrgb, SpvImageFormatUnknown},
-                       TestData{type::TexelFormat::kBgra8Unorm, SpvImageFormatUnknown},
-                       TestData{type::TexelFormat::kBgra8UnormSrgb, SpvImageFormatUnknown},
-                       TestData{type::TexelFormat::kRgb10A2Unorm, SpvImageFormatRgb10A2, true},
-                       TestData{type::TexelFormat::kRg11B10Float, SpvImageFormatR11fG11fB10f, true},
-                     */
-                             TestData{type::TexelFormat::kR32Uint, SpvImageFormatR32ui},
-                             TestData{type::TexelFormat::kR32Sint, SpvImageFormatR32i},
-                             TestData{type::TexelFormat::kR32Float, SpvImageFormatR32f},
-                             TestData{type::TexelFormat::kRgba8Unorm, SpvImageFormatRgba8},
-                             TestData{type::TexelFormat::kRgba8Snorm, SpvImageFormatRgba8Snorm},
-                             TestData{type::TexelFormat::kRgba8Uint, SpvImageFormatRgba8ui},
-                             TestData{type::TexelFormat::kRgba8Sint, SpvImageFormatRgba8i},
-                             TestData{type::TexelFormat::kRg32Uint, SpvImageFormatRg32ui, true},
-                             TestData{type::TexelFormat::kRg32Sint, SpvImageFormatRg32i, true},
-                             TestData{type::TexelFormat::kRg32Float, SpvImageFormatRg32f, true},
-                             TestData{type::TexelFormat::kRgba16Uint, SpvImageFormatRgba16ui},
-                             TestData{type::TexelFormat::kRgba16Sint, SpvImageFormatRgba16i},
-                             TestData{type::TexelFormat::kRgba16Float, SpvImageFormatRgba16f},
-                             TestData{type::TexelFormat::kRgba32Uint, SpvImageFormatRgba32ui},
-                             TestData{type::TexelFormat::kRgba32Sint, SpvImageFormatRgba32i},
-                             TestData{type::TexelFormat::kRgba32Float, SpvImageFormatRgba32f}));
+INSTANTIATE_TEST_SUITE_P(
+    BuilderTest,
+    ImageFormatConversionTest,
+    testing::Values(
+        /* WGSL unsupported formats
+  TestData{builtin::TexelFormat::kR8Unorm, SpvImageFormatR8, true},
+  TestData{builtin::TexelFormat::kR8Snorm, SpvImageFormatR8Snorm, true},
+  TestData{builtin::TexelFormat::kR8Uint, SpvImageFormatR8ui, true},
+  TestData{builtin::TexelFormat::kR8Sint, SpvImageFormatR8i, true},
+  TestData{builtin::TexelFormat::kR16Uint, SpvImageFormatR16ui, true},
+  TestData{builtin::TexelFormat::kR16Sint, SpvImageFormatR16i, true},
+  TestData{builtin::TexelFormat::kR16Float, SpvImageFormatR16f, true},
+  TestData{builtin::TexelFormat::kRg8Unorm, SpvImageFormatRg8, true},
+  TestData{builtin::TexelFormat::kRg8Snorm, SpvImageFormatRg8Snorm, true},
+  TestData{builtin::TexelFormat::kRg8Uint, SpvImageFormatRg8ui, true},
+  TestData{builtin::TexelFormat::kRg8Sint, SpvImageFormatRg8i, true},
+  TestData{builtin::TexelFormat::kRg16Uint, SpvImageFormatRg16ui, true},
+  TestData{builtin::TexelFormat::kRg16Sint, SpvImageFormatRg16i, true},
+  TestData{builtin::TexelFormat::kRg16Float, SpvImageFormatRg16f, true},
+  TestData{builtin::TexelFormat::kRgba8UnormSrgb, SpvImageFormatUnknown},
+  TestData{builtin::TexelFormat::kBgra8Unorm, SpvImageFormatUnknown},
+  TestData{builtin::TexelFormat::kBgra8UnormSrgb, SpvImageFormatUnknown},
+  TestData{builtin::TexelFormat::kRgb10A2Unorm, SpvImageFormatRgb10A2, true},
+  TestData{builtin::TexelFormat::kRg11B10Float, SpvImageFormatR11fG11fB10f, true},
+*/
+        TestData{builtin::TexelFormat::kR32Uint, SpvImageFormatR32ui},
+        TestData{builtin::TexelFormat::kR32Sint, SpvImageFormatR32i},
+        TestData{builtin::TexelFormat::kR32Float, SpvImageFormatR32f},
+        TestData{builtin::TexelFormat::kRgba8Unorm, SpvImageFormatRgba8},
+        TestData{builtin::TexelFormat::kRgba8Snorm, SpvImageFormatRgba8Snorm},
+        TestData{builtin::TexelFormat::kRgba8Uint, SpvImageFormatRgba8ui},
+        TestData{builtin::TexelFormat::kRgba8Sint, SpvImageFormatRgba8i},
+        TestData{builtin::TexelFormat::kRg32Uint, SpvImageFormatRg32ui, true},
+        TestData{builtin::TexelFormat::kRg32Sint, SpvImageFormatRg32i, true},
+        TestData{builtin::TexelFormat::kRg32Float, SpvImageFormatRg32f, true},
+        TestData{builtin::TexelFormat::kRgba16Uint, SpvImageFormatRgba16ui},
+        TestData{builtin::TexelFormat::kRgba16Sint, SpvImageFormatRgba16i},
+        TestData{builtin::TexelFormat::kRgba16Float, SpvImageFormatRgba16f},
+        TestData{builtin::TexelFormat::kRgba32Uint, SpvImageFormatRgba32ui},
+        TestData{builtin::TexelFormat::kRgba32Sint, SpvImageFormatRgba32i},
+        TestData{builtin::TexelFormat::kRgba32Float, SpvImageFormatRgba32f}));
 
 }  // namespace
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/builder_function_test.cc b/src/tint/writer/spirv/builder_function_test.cc
index 618a84e..5cf97ea 100644
--- a/src/tint/writer/spirv/builder_function_test.cc
+++ b/src/tint/writer/spirv/builder_function_test.cc
@@ -61,7 +61,7 @@
 }
 
 TEST_F(BuilderTest, Function_Terminator_ReturnValue) {
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
 
     Func("a_func", utils::Empty, ty.f32(), utils::Vector{Return("a")}, utils::Empty);
 
@@ -198,7 +198,7 @@
 
     auto* s = Structure("Data", utils::Vector{Member("d", ty.f32())});
 
-    GlobalVar("data", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("data", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(0_a));
 
     {
diff --git a/src/tint/writer/spirv/builder_function_variable_test.cc b/src/tint/writer/spirv/builder_function_variable_test.cc
index 47f1ed2..72cf12b 100644
--- a/src/tint/writer/spirv/builder_function_variable_test.cc
+++ b/src/tint/writer/spirv/builder_function_variable_test.cc
@@ -23,7 +23,7 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, FunctionVar_NoAddressSpace) {
-    auto* v = Var("var", ty.f32(), type::AddressSpace::kFunction);
+    auto* v = Var("var", ty.f32(), builtin::AddressSpace::kFunction);
     WrapInFunction(v);
 
     spirv::Builder& b = Build();
@@ -45,7 +45,7 @@
 
 TEST_F(BuilderTest, FunctionVar_WithConstantInitializer) {
     auto* init = vec3<f32>(1_f, 1_f, 3_f);
-    auto* v = Var("var", ty.vec3<f32>(), type::AddressSpace::kFunction, init);
+    auto* v = Var("var", ty.vec3<f32>(), builtin::AddressSpace::kFunction, init);
     WrapInFunction(v);
 
     spirv::Builder& b = Build();
diff --git a/src/tint/writer/spirv/builder_global_variable_test.cc b/src/tint/writer/spirv/builder_global_variable_test.cc
index ea9c6a8..2f551ff 100644
--- a/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -26,7 +26,7 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, GlobalVar_WithAddressSpace) {
-    auto* v = GlobalVar("var", ty.f32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     spirv::Builder& b = Build();
 
@@ -43,7 +43,7 @@
 TEST_F(BuilderTest, GlobalVar_WithInitializer) {
     auto* init = vec3<f32>(1_f, 1_f, 3_f);
 
-    auto* v = GlobalVar("var", ty.vec3<f32>(), type::AddressSpace::kPrivate, init);
+    auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, init);
 
     spirv::Builder& b = Build();
 
@@ -67,7 +67,7 @@
     // var v = c;
 
     auto* c = GlobalConst("c", Expr(42_a));
-    GlobalVar("v", type::AddressSpace::kPrivate, Expr(c));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
 
@@ -92,7 +92,7 @@
     // var v = c;
 
     auto* c = GlobalConst("c", vec3<f32>(1_f, 2_f, 3_f));
-    GlobalVar("v", type::AddressSpace::kPrivate, Expr(c));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
 
@@ -122,7 +122,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* c = GlobalConst("c", vec3<f16>(1_h, 2_h, 3_h));
-    GlobalVar("v", type::AddressSpace::kPrivate, Expr(c));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
 
@@ -151,7 +151,7 @@
     // var v = c;
 
     auto* c = GlobalConst("c", Call(ty.vec3<Infer>(), 1_a, 2_a, 3_a));
-    GlobalVar("v", type::AddressSpace::kPrivate, Expr(c));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
 
@@ -180,7 +180,7 @@
     // var v = c;
 
     auto* c = GlobalConst("c", Call(ty.vec3<Infer>(), 1._a, 2._a, 3._a));
-    GlobalVar("v", type::AddressSpace::kPrivate, Expr(c));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
 
@@ -209,7 +209,7 @@
     // var v = c;
 
     auto* c = GlobalConst("c", vec3<f32>(vec2<f32>(1_f, 2_f), 3_f));
-    GlobalVar("v", type::AddressSpace::kPrivate, Expr(c));
+    GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
 
@@ -252,7 +252,7 @@
 
 struct BuiltinData {
     builtin::BuiltinValue builtin;
-    type::AddressSpace storage;
+    builtin::AddressSpace storage;
     SpvBuiltIn result;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
@@ -270,37 +270,39 @@
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest_Type,
     BuiltinDataTest,
-    testing::Values(
-        BuiltinData{builtin::BuiltinValue::kUndefined, type::AddressSpace::kNone, SpvBuiltInMax},
-        BuiltinData{builtin::BuiltinValue::kPosition, type::AddressSpace::kIn, SpvBuiltInFragCoord},
-        BuiltinData{builtin::BuiltinValue::kPosition, type::AddressSpace::kOut, SpvBuiltInPosition},
-        BuiltinData{
-            builtin::BuiltinValue::kVertexIndex,
-            type::AddressSpace::kIn,
-            SpvBuiltInVertexIndex,
-        },
-        BuiltinData{builtin::BuiltinValue::kInstanceIndex, type::AddressSpace::kIn,
-                    SpvBuiltInInstanceIndex},
-        BuiltinData{builtin::BuiltinValue::kFrontFacing, type::AddressSpace::kIn,
-                    SpvBuiltInFrontFacing},
-        BuiltinData{builtin::BuiltinValue::kFragDepth, type::AddressSpace::kOut,
-                    SpvBuiltInFragDepth},
-        BuiltinData{builtin::BuiltinValue::kLocalInvocationId, type::AddressSpace::kIn,
-                    SpvBuiltInLocalInvocationId},
-        BuiltinData{builtin::BuiltinValue::kLocalInvocationIndex, type::AddressSpace::kIn,
-                    SpvBuiltInLocalInvocationIndex},
-        BuiltinData{builtin::BuiltinValue::kGlobalInvocationId, type::AddressSpace::kIn,
-                    SpvBuiltInGlobalInvocationId},
-        BuiltinData{builtin::BuiltinValue::kWorkgroupId, type::AddressSpace::kIn,
-                    SpvBuiltInWorkgroupId},
-        BuiltinData{builtin::BuiltinValue::kNumWorkgroups, type::AddressSpace::kIn,
-                    SpvBuiltInNumWorkgroups},
-        BuiltinData{builtin::BuiltinValue::kSampleIndex, type::AddressSpace::kIn,
-                    SpvBuiltInSampleId},
-        BuiltinData{builtin::BuiltinValue::kSampleMask, type::AddressSpace::kIn,
-                    SpvBuiltInSampleMask},
-        BuiltinData{builtin::BuiltinValue::kSampleMask, type::AddressSpace::kOut,
-                    SpvBuiltInSampleMask}));
+    testing::Values(BuiltinData{builtin::BuiltinValue::kUndefined,
+                                builtin::AddressSpace::kUndefined, SpvBuiltInMax},
+                    BuiltinData{builtin::BuiltinValue::kPosition, builtin::AddressSpace::kIn,
+                                SpvBuiltInFragCoord},
+                    BuiltinData{builtin::BuiltinValue::kPosition, builtin::AddressSpace::kOut,
+                                SpvBuiltInPosition},
+                    BuiltinData{
+                        builtin::BuiltinValue::kVertexIndex,
+                        builtin::AddressSpace::kIn,
+                        SpvBuiltInVertexIndex,
+                    },
+                    BuiltinData{builtin::BuiltinValue::kInstanceIndex, builtin::AddressSpace::kIn,
+                                SpvBuiltInInstanceIndex},
+                    BuiltinData{builtin::BuiltinValue::kFrontFacing, builtin::AddressSpace::kIn,
+                                SpvBuiltInFrontFacing},
+                    BuiltinData{builtin::BuiltinValue::kFragDepth, builtin::AddressSpace::kOut,
+                                SpvBuiltInFragDepth},
+                    BuiltinData{builtin::BuiltinValue::kLocalInvocationId,
+                                builtin::AddressSpace::kIn, SpvBuiltInLocalInvocationId},
+                    BuiltinData{builtin::BuiltinValue::kLocalInvocationIndex,
+                                builtin::AddressSpace::kIn, SpvBuiltInLocalInvocationIndex},
+                    BuiltinData{builtin::BuiltinValue::kGlobalInvocationId,
+                                builtin::AddressSpace::kIn, SpvBuiltInGlobalInvocationId},
+                    BuiltinData{builtin::BuiltinValue::kWorkgroupId, builtin::AddressSpace::kIn,
+                                SpvBuiltInWorkgroupId},
+                    BuiltinData{builtin::BuiltinValue::kNumWorkgroups, builtin::AddressSpace::kIn,
+                                SpvBuiltInNumWorkgroups},
+                    BuiltinData{builtin::BuiltinValue::kSampleIndex, builtin::AddressSpace::kIn,
+                                SpvBuiltInSampleId},
+                    BuiltinData{builtin::BuiltinValue::kSampleMask, builtin::AddressSpace::kIn,
+                                SpvBuiltInSampleMask},
+                    BuiltinData{builtin::BuiltinValue::kSampleMask, builtin::AddressSpace::kOut,
+                                SpvBuiltInSampleMask}));
 
 TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
     // struct A {
@@ -313,7 +315,7 @@
                                  Member("b", ty.i32()),
                              });
 
-    GlobalVar("b", ty.Of(A), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
+    GlobalVar("b", ty.Of(A), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(0_a),
               Group(0_a));
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -355,7 +357,7 @@
 
     auto* A = Structure("A", utils::Vector{Member("a", ty.i32())});
     auto* B = Alias("B", ty.Of(A));
-    GlobalVar("b", ty.Of(B), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
+    GlobalVar("b", ty.Of(B), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(0_a),
               Group(0_a));
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -395,7 +397,7 @@
 
     auto* A = Structure("A", utils::Vector{Member("a", ty.i32())});
     auto* B = Alias("B", ty.Of(A));
-    GlobalVar("b", ty.Of(B), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
+    GlobalVar("b", ty.Of(B), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(0_a),
               Group(0_a));
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -434,10 +436,10 @@
     // var<storage, read_write> c : A
 
     auto* A = Structure("A", utils::Vector{Member("a", ty.i32())});
-    GlobalVar("b", ty.Of(A), type::AddressSpace::kStorage, type::Access::kRead, Group(0_a),
+    GlobalVar("b", ty.Of(A), builtin::AddressSpace::kStorage, builtin::Access::kRead, Group(0_a),
               Binding(0_a));
-    GlobalVar("c", ty.Of(A), type::AddressSpace::kStorage, type::Access::kReadWrite, Group(1_a),
-              Binding(0_a));
+    GlobalVar("c", ty.Of(A), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
+              Group(1_a), Binding(0_a));
 
     spirv::Builder& b = SanitizeAndBuild();
 
@@ -475,8 +477,8 @@
 TEST_F(BuilderTest, GlobalVar_TextureStorageWriteOnly) {
     // var<uniform_constant> a : texture_storage_2d<r32uint, write>;
 
-    auto type = ty.storage_texture(type::TextureDimension::k2d, type::TexelFormat::kR32Uint,
-                                   type::Access::kWrite);
+    auto type = ty.storage_texture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint,
+                                   builtin::Access::kWrite);
 
     auto* var_a = GlobalVar("a", type, Binding(0_a), Group(0_a));
 
@@ -497,16 +499,16 @@
 
 TEST_F(BuilderTest, GlobalVar_WorkgroupWithZeroInit) {
     auto type_scalar = ty.i32();
-    auto* var_scalar = GlobalVar("a", type_scalar, type::AddressSpace::kWorkgroup);
+    auto* var_scalar = GlobalVar("a", type_scalar, builtin::AddressSpace::kWorkgroup);
 
     auto type_array = ty.array<f32, 16>();
-    auto* var_array = GlobalVar("b", type_array, type::AddressSpace::kWorkgroup);
+    auto* var_array = GlobalVar("b", type_array, builtin::AddressSpace::kWorkgroup);
 
     auto* type_struct = Structure("C", utils::Vector{
                                            Member("a", ty.i32()),
                                            Member("b", ty.i32()),
                                        });
-    auto* var_struct = GlobalVar("c", ty.Of(type_struct), type::AddressSpace::kWorkgroup);
+    auto* var_struct = GlobalVar("c", ty.Of(type_struct), builtin::AddressSpace::kWorkgroup);
 
     program = std::make_unique<Program>(std::move(*this));
 
diff --git a/src/tint/writer/spirv/builder_ident_expression_test.cc b/src/tint/writer/spirv/builder_ident_expression_test.cc
index 4db5d42..7c56ba1 100644
--- a/src/tint/writer/spirv/builder_ident_expression_test.cc
+++ b/src/tint/writer/spirv/builder_ident_expression_test.cc
@@ -41,7 +41,7 @@
 }
 
 TEST_F(BuilderTest, IdentifierExpression_GlobalVar) {
-    auto* v = GlobalVar("var", ty.f32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("var", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* expr = Expr("var");
     WrapInFunction(expr);
@@ -85,7 +85,7 @@
 }
 
 TEST_F(BuilderTest, IdentifierExpression_FunctionVar) {
-    auto* v = Var("var", ty.f32(), type::AddressSpace::kFunction);
+    auto* v = Var("var", ty.f32(), builtin::AddressSpace::kFunction);
     auto* expr = Expr("var");
     WrapInFunction(v, expr);
 
@@ -109,7 +109,7 @@
 }
 
 TEST_F(BuilderTest, IdentifierExpression_Load) {
-    auto* var = GlobalVar("var", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("var", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* expr = Add("var", "var");
     WrapInFunction(expr);
 
diff --git a/src/tint/writer/spirv/builder_if_test.cc b/src/tint/writer/spirv/builder_if_test.cc
index 6462200..031ed68 100644
--- a/src/tint/writer/spirv/builder_if_test.cc
+++ b/src/tint/writer/spirv/builder_if_test.cc
@@ -68,7 +68,7 @@
     //   v = 2;
     // }
 
-    auto* var = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* body = Block(Assign("v", 2_i));
     auto* expr = If(true, body);
     WrapInFunction(expr);
@@ -104,7 +104,7 @@
     //   v = 3i;
     // }
 
-    auto* var = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* body = Block(Assign("v", 2_i));
     auto* else_body = Block(Assign("v", 3_i));
 
@@ -146,7 +146,7 @@
     //   v = 3i;
     // }
 
-    auto* var = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* body = Block(Assign("v", 2_i));
     auto* else_body = Block(Assign("v", 3_i));
 
@@ -197,7 +197,7 @@
     //   v = 5i;
     // }
 
-    auto* var = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* body = Block(Assign("v", 2_i));
     auto* elseif_1_body = Block(Assign("v", 3_i));
     auto* elseif_2_body = Block(Assign("v", 4_i));
@@ -562,7 +562,7 @@
     // if (a) {
     // }
 
-    auto* var = GlobalVar("a", ty.bool_(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate);
     auto* fn = Func("f", utils::Empty, ty.void_(),
                     utils::Vector{
                         If("a", Block()),
diff --git a/src/tint/writer/spirv/builder_loop_test.cc b/src/tint/writer/spirv/builder_loop_test.cc
index ef8dfa8..5fc15b8 100644
--- a/src/tint/writer/spirv/builder_loop_test.cc
+++ b/src/tint/writer/spirv/builder_loop_test.cc
@@ -54,7 +54,7 @@
     //   break;
     // }
 
-    auto* var = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* body = Block(Assign("v", 2_i),  //
                        Break());
 
@@ -96,7 +96,7 @@
     //   }
     // }
 
-    auto* var = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
+    auto* var = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* body = Block(Assign("v", 2_i),  //
                        Break());
     auto* continuing = Block(Assign("v", 3_i));
diff --git a/src/tint/writer/spirv/builder_switch_test.cc b/src/tint/writer/spirv/builder_switch_test.cc
index a04a194..7e0bd18 100644
--- a/src/tint/writer/spirv/builder_switch_test.cc
+++ b/src/tint/writer/spirv/builder_switch_test.cc
@@ -56,8 +56,8 @@
     //   default: {}
     // }
 
-    auto* v = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
-    auto* a = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -113,8 +113,8 @@
     //   default: {}
     // }
 
-    auto* v = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
-    auto* a = GlobalVar("a", ty.u32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate);
 
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -170,8 +170,8 @@
     //     v = 1i;
     //  }
 
-    auto* v = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
-    auto* a = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -220,8 +220,8 @@
     //      v = 3i;
     //  }
 
-    auto* v = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
-    auto* a = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -280,8 +280,8 @@
     //      v = 2i;
     //  }
 
-    auto* v = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
-    auto* a = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{Switch(Expr("a"),                      //
@@ -337,8 +337,8 @@
     //   default: {}
     // }
 
-    auto* v = GlobalVar("v", ty.i32(), type::AddressSpace::kPrivate);
-    auto* a = GlobalVar("a", ty.i32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
diff --git a/src/tint/writer/spirv/builder_type_test.cc b/src/tint/writer/spirv/builder_type_test.cc
index cf35662..55b92c6 100644
--- a/src/tint/writer/spirv/builder_type_test.cc
+++ b/src/tint/writer/spirv/builder_type_test.cc
@@ -29,8 +29,8 @@
 TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
     auto ary = ty.array(ty.i32());
     auto* str = Structure("S", utils::Vector{Member("x", ary)});
-    GlobalVar("a", ty.Of(str), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
-              Group(0_a));
+    GlobalVar("a", ty.Of(str), builtin::AddressSpace::kStorage, builtin::Access::kRead,
+              Binding(0_a), Group(0_a));
     ast::Type type = str->members[0]->type;
 
     spirv::Builder& b = Build();
@@ -47,8 +47,8 @@
 TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
     auto ary = ty.array(ty.i32());
     auto* str = Structure("S", utils::Vector{Member("x", ary)});
-    GlobalVar("a", ty.Of(str), type::AddressSpace::kStorage, type::Access::kRead, Binding(0_a),
-              Group(0_a));
+    GlobalVar("a", ty.Of(str), builtin::AddressSpace::kStorage, builtin::Access::kRead,
+              Binding(0_a), Group(0_a));
     ast::Type type = str->members[0]->type;
 
     spirv::Builder& b = Build();
@@ -64,7 +64,7 @@
 
 TEST_F(BuilderTest_Type, GenerateArray) {
     auto ary = ty.array<i32, 4>();
-    ast::Type type = GlobalVar("a", ary, type::AddressSpace::kPrivate)->type;
+    ast::Type type = GlobalVar("a", ary, builtin::AddressSpace::kPrivate)->type;
 
     spirv::Builder& b = Build();
 
@@ -81,7 +81,7 @@
 
 TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
     auto ary = ty.array<i32, 4>(utils::Vector{Stride(16)});
-    ast::Type ty = GlobalVar("a", ary, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("a", ary, builtin::AddressSpace::kPrivate)->type;
 
     spirv::Builder& b = Build();
 
@@ -101,7 +101,7 @@
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedArray) {
     auto ary = ty.array<i32, 4>();
-    ast::Type ty = GlobalVar("a", ary, type::AddressSpace::kPrivate)->type;
+    ast::Type ty = GlobalVar("a", ary, builtin::AddressSpace::kPrivate)->type;
 
     spirv::Builder& b = Build();
 
@@ -296,7 +296,8 @@
 
 TEST_F(BuilderTest_Type, GeneratePtr) {
     auto* i32 = create<type::I32>();
-    auto* ptr = create<type::Pointer>(i32, type::AddressSpace::kOut, type::Access::kReadWrite);
+    auto* ptr =
+        create<type::Pointer>(i32, builtin::AddressSpace::kOut, builtin::Access::kReadWrite);
 
     spirv::Builder& b = Build();
 
@@ -311,7 +312,8 @@
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
     auto* i32 = create<type::I32>();
-    auto* ptr = create<type::Pointer>(i32, type::AddressSpace::kOut, type::Access::kReadWrite);
+    auto* ptr =
+        create<type::Pointer>(i32, builtin::AddressSpace::kOut, builtin::Access::kReadWrite);
 
     spirv::Builder& b = Build();
 
@@ -605,7 +607,7 @@
 }
 
 struct PtrData {
-    type::AddressSpace ast_class;
+    builtin::AddressSpace ast_class;
     SpvStorageClass result;
 };
 inline std::ostream& operator<<(std::ostream& out, PtrData data) {
@@ -623,15 +625,15 @@
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest_Type,
     PtrDataTest,
-    testing::Values(PtrData{type::AddressSpace::kNone, SpvStorageClassMax},
-                    PtrData{type::AddressSpace::kIn, SpvStorageClassInput},
-                    PtrData{type::AddressSpace::kOut, SpvStorageClassOutput},
-                    PtrData{type::AddressSpace::kUniform, SpvStorageClassUniform},
-                    PtrData{type::AddressSpace::kWorkgroup, SpvStorageClassWorkgroup},
-                    PtrData{type::AddressSpace::kHandle, SpvStorageClassUniformConstant},
-                    PtrData{type::AddressSpace::kStorage, SpvStorageClassStorageBuffer},
-                    PtrData{type::AddressSpace::kPrivate, SpvStorageClassPrivate},
-                    PtrData{type::AddressSpace::kFunction, SpvStorageClassFunction}));
+    testing::Values(PtrData{builtin::AddressSpace::kUndefined, SpvStorageClassMax},
+                    PtrData{builtin::AddressSpace::kIn, SpvStorageClassInput},
+                    PtrData{builtin::AddressSpace::kOut, SpvStorageClassOutput},
+                    PtrData{builtin::AddressSpace::kUniform, SpvStorageClassUniform},
+                    PtrData{builtin::AddressSpace::kWorkgroup, SpvStorageClassWorkgroup},
+                    PtrData{builtin::AddressSpace::kHandle, SpvStorageClassUniformConstant},
+                    PtrData{builtin::AddressSpace::kStorage, SpvStorageClassStorageBuffer},
+                    PtrData{builtin::AddressSpace::kPrivate, SpvStorageClassPrivate},
+                    PtrData{builtin::AddressSpace::kFunction, SpvStorageClassFunction}));
 
 TEST_F(BuilderTest_Type, DepthTexture_Generate_2d) {
     auto* two_d = create<type::DepthTexture>(type::TextureDimension::k2d);
@@ -862,8 +864,8 @@
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
-    auto s = ty.storage_texture(type::TextureDimension::k1d, type::TexelFormat::kR32Float,
-                                type::Access::kWrite);
+    auto s = ty.storage_texture(type::TextureDimension::k1d, builtin::TexelFormat::kR32Float,
+                                builtin::Access::kWrite);
 
     ast::Type ty = GlobalVar("test_var", s, Binding(0_a), Group(0_a))->type;
 
@@ -877,8 +879,8 @@
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
-    auto s = ty.storage_texture(type::TextureDimension::k2d, type::TexelFormat::kR32Float,
-                                type::Access::kWrite);
+    auto s = ty.storage_texture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Float,
+                                builtin::Access::kWrite);
 
     ast::Type ty = GlobalVar("test_var", s, Binding(0_a), Group(0_a))->type;
 
@@ -892,8 +894,8 @@
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
-    auto s = ty.storage_texture(type::TextureDimension::k2dArray, type::TexelFormat::kR32Float,
-                                type::Access::kWrite);
+    auto s = ty.storage_texture(type::TextureDimension::k2dArray, builtin::TexelFormat::kR32Float,
+                                builtin::Access::kWrite);
 
     ast::Type ty = GlobalVar("test_var", s, Binding(0_a), Group(0_a))->type;
 
@@ -907,8 +909,8 @@
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
-    auto s = ty.storage_texture(type::TextureDimension::k3d, type::TexelFormat::kR32Float,
-                                type::Access::kWrite);
+    auto s = ty.storage_texture(type::TextureDimension::k3d, builtin::TexelFormat::kR32Float,
+                                builtin::Access::kWrite);
 
     ast::Type ty = GlobalVar("test_var", s, Binding(0_a), Group(0_a))->type;
 
@@ -922,8 +924,8 @@
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeFloat_Format_r32float) {
-    auto s = ty.storage_texture(type::TextureDimension::k2d, type::TexelFormat::kR32Float,
-                                type::Access::kWrite);
+    auto s = ty.storage_texture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Float,
+                                builtin::Access::kWrite);
 
     ast::Type ty = GlobalVar("test_var", s, Binding(0_a), Group(0_a))->type;
 
@@ -937,8 +939,8 @@
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeSint_Format_r32sint) {
-    auto s = ty.storage_texture(type::TextureDimension::k2d, type::TexelFormat::kR32Sint,
-                                type::Access::kWrite);
+    auto s = ty.storage_texture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Sint,
+                                builtin::Access::kWrite);
 
     ast::Type ty = GlobalVar("test_var", s, Binding(0_a), Group(0_a))->type;
 
@@ -952,8 +954,8 @@
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeUint_Format_r32uint) {
-    auto s = ty.storage_texture(type::TextureDimension::k2d, type::TexelFormat::kR32Uint,
-                                type::Access::kWrite);
+    auto s = ty.storage_texture(type::TextureDimension::k2d, builtin::TexelFormat::kR32Uint,
+                                builtin::Access::kWrite);
 
     ast::Type ty = GlobalVar("test_var", s, Binding(0_a), Group(0_a))->type;
 
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index 10bd9d8..4363b62 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -34,8 +34,6 @@
 #include "src/tint/ast/workgroup_attribute.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/switch_statement.h"
-#include "src/tint/type/access.h"
-#include "src/tint/type/texture_dimension.h"
 #include "src/tint/utils/math.h"
 #include "src/tint/utils/scoped_assignment.h"
 #include "src/tint/writer/float_to_string.h"
@@ -365,9 +363,9 @@
     return true;
 }
 
-bool GeneratorImpl::EmitImageFormat(std::ostream& out, const type::TexelFormat fmt) {
+bool GeneratorImpl::EmitImageFormat(std::ostream& out, const builtin::TexelFormat fmt) {
     switch (fmt) {
-        case type::TexelFormat::kUndefined:
+        case builtin::TexelFormat::kUndefined:
             diagnostics_.add_error(diag::System::Writer, "unknown image format");
             return false;
         default:
@@ -376,24 +374,6 @@
     return true;
 }
 
-bool GeneratorImpl::EmitAccess(std::ostream& out, const type::Access access) {
-    switch (access) {
-        case type::Access::kRead:
-            out << "read";
-            return true;
-        case type::Access::kWrite:
-            out << "write";
-            return true;
-        case type::Access::kReadWrite:
-            out << "read_write";
-            return true;
-        default:
-            break;
-    }
-    diagnostics_.add_error(diag::System::Writer, "unknown access");
-    return false;
-}
-
 bool GeneratorImpl::EmitStructType(const ast::Struct* str) {
     if (str->attributes.Length()) {
         if (!EmitAttributes(line(), str->attributes)) {
@@ -473,17 +453,18 @@
         v,  //
         [&](const ast::Var* var) {
             out << "var";
-            auto address_space = var->declared_address_space;
-            auto ac = var->declared_access;
-            if (address_space != type::AddressSpace::kNone || ac != type::Access::kUndefined) {
-                out << "<" << address_space;
-                if (ac != type::Access::kUndefined) {
+            if (var->declared_address_space || var->declared_access) {
+                out << "<";
+                TINT_DEFER(out << ">");
+                if (!EmitExpression(out, var->declared_address_space)) {
+                    return false;
+                }
+                if (var->declared_access) {
                     out << ", ";
-                    if (!EmitAccess(out, ac)) {
+                    if (!EmitExpression(out, var->declared_access)) {
                         return false;
                     }
                 }
-                out << ">";
             }
             return true;
         },
@@ -583,16 +564,26 @@
                 return true;
             },
             [&](const ast::BuiltinAttribute* builtin) {
-                out << "builtin(" << builtin->builtin << ")";
+                out << "builtin(";
+                if (!EmitExpression(out, builtin->builtin)) {
+                    return false;
+                }
+                out << ")";
                 return true;
             },
             [&](const ast::DiagnosticAttribute* diagnostic) {
                 return EmitDiagnosticControl(out, diagnostic->control);
             },
             [&](const ast::InterpolateAttribute* interpolate) {
-                out << "interpolate(" << interpolate->type;
-                if (interpolate->sampling != ast::InterpolationSampling::kUndefined) {
-                    out << ", " << interpolate->sampling;
+                out << "interpolate(";
+                if (!EmitExpression(out, interpolate->type)) {
+                    return false;
+                }
+                if (interpolate->sampling) {
+                    out << ", ";
+                    if (!EmitExpression(out, interpolate->sampling)) {
+                        return false;
+                    }
                 }
                 out << ")";
                 return true;
@@ -609,6 +600,10 @@
                 out << ")";
                 return true;
             },
+            [&](const ast::MustUseAttribute*) {
+                out << "must_use";
+                return true;
+            },
             [&](const ast::StructMemberOffsetAttribute* offset) {
                 out << "offset(";
                 if (!EmitExpression(out, offset->expr)) {
diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h
index 56c0dfb..abfee1d 100644
--- a/src/tint/writer/wgsl/generator_impl.h
+++ b/src/tint/writer/wgsl/generator_impl.h
@@ -35,7 +35,6 @@
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/program.h"
 #include "src/tint/sem/struct.h"
-#include "src/tint/type/storage_texture.h"
 #include "src/tint/writer/text_generator.h"
 
 namespace tint::writer::wgsl {
@@ -208,12 +207,7 @@
     /// @param out the output stream
     /// @param fmt the format to generate
     /// @returns true if the format is emitted
-    bool EmitImageFormat(std::ostream& out, const type::TexelFormat fmt);
-    /// Handles emitting an access control
-    /// @param out the output stream
-    /// @param access the access to generate
-    /// @returns true if the access is emitted
-    bool EmitAccess(std::ostream& out, const type::Access access);
+    bool EmitImageFormat(std::ostream& out, const builtin::TexelFormat fmt);
     /// Handles a unary op expression
     /// @param out the output stream
     /// @param expr the expression to emit
diff --git a/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc b/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
index ed05a2d..31e7e6b 100644
--- a/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
@@ -22,7 +22,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, IndexAccessor) {
-    GlobalVar("ary", ty.array<i32, 10>(), type::AddressSpace::kPrivate);
+    GlobalVar("ary", ty.array<i32, 10>(), builtin::AddressSpace::kPrivate);
     auto* expr = IndexAccessor("ary", 5_i);
     WrapInFunction(expr);
 
@@ -34,7 +34,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, IndexAccessor_OfDref) {
-    GlobalVar("ary", ty.array<i32, 10>(), type::AddressSpace::kPrivate);
+    GlobalVar("ary", ty.array<i32, 10>(), builtin::AddressSpace::kPrivate);
 
     auto* p = Let("p", AddressOf("ary"));
     auto* expr = IndexAccessor(Deref("p"), 5_i);
diff --git a/src/tint/writer/wgsl/generator_impl_assign_test.cc b/src/tint/writer/wgsl/generator_impl_assign_test.cc
index 3a6dd1a..c802cb1 100644
--- a/src/tint/writer/wgsl/generator_impl_assign_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_assign_test.cc
@@ -20,8 +20,8 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Assign) {
-    auto* lhs = GlobalVar("lhs", ty.i32(), type::AddressSpace::kPrivate);
-    auto* rhs = GlobalVar("rhs", ty.i32(), type::AddressSpace::kPrivate);
+    auto* lhs = GlobalVar("lhs", ty.i32(), builtin::AddressSpace::kPrivate);
+    auto* rhs = GlobalVar("rhs", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* assign = Assign(lhs, rhs);
     WrapInFunction(assign);
 
diff --git a/src/tint/writer/wgsl/generator_impl_binary_test.cc b/src/tint/writer/wgsl/generator_impl_binary_test.cc
index 2770e5c..d86b1c4 100644
--- a/src/tint/writer/wgsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_binary_test.cc
@@ -37,8 +37,8 @@
         }
     };
 
-    GlobalVar("left", op_ty(), type::AddressSpace::kPrivate);
-    GlobalVar("right", op_ty(), type::AddressSpace::kPrivate);
+    GlobalVar("left", op_ty(), builtin::AddressSpace::kPrivate);
+    GlobalVar("right", op_ty(), builtin::AddressSpace::kPrivate);
     auto* left = Expr("left");
     auto* right = Expr("right");
 
diff --git a/src/tint/writer/wgsl/generator_impl_call_test.cc b/src/tint/writer/wgsl/generator_impl_call_test.cc
index 39a287c..4492628 100644
--- a/src/tint/writer/wgsl/generator_impl_call_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_call_test.cc
@@ -48,8 +48,8 @@
          utils::Vector{
              Return(1.23_f),
          });
-    GlobalVar("param1", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("my_func", "param1", "param2");
     WrapInFunction(call);
@@ -68,8 +68,8 @@
              Param(Sym(), ty.f32()),
          },
          ty.void_(), utils::Empty, utils::Empty);
-    GlobalVar("param1", ty.f32(), type::AddressSpace::kPrivate);
-    GlobalVar("param2", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("param1", ty.f32(), builtin::AddressSpace::kPrivate);
+    GlobalVar("param2", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* call = Call("my_func", "param1", "param2");
     auto* stmt = CallStmt(call);
diff --git a/src/tint/writer/wgsl/generator_impl_initializer_test.cc b/src/tint/writer/wgsl/generator_impl_constructor_test.cc
similarity index 83%
rename from src/tint/writer/wgsl/generator_impl_initializer_test.cc
rename to src/tint/writer/wgsl/generator_impl_constructor_test.cc
index 0d5686e..c815f42 100644
--- a/src/tint/writer/wgsl/generator_impl_initializer_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_constructor_test.cc
@@ -22,9 +22,9 @@
 namespace tint::writer::wgsl {
 namespace {
 
-using WgslGeneratorImplTest = TestHelper;
+using WgslGeneratorImplTest_Constructor = TestHelper;
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Bool) {
+TEST_F(WgslGeneratorImplTest_Constructor, Bool) {
     WrapInFunction(Expr(false));
 
     GeneratorImpl& gen = Build();
@@ -33,7 +33,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Int) {
+TEST_F(WgslGeneratorImplTest_Constructor, Int) {
     WrapInFunction(Expr(-12345_i));
 
     GeneratorImpl& gen = Build();
@@ -42,7 +42,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_UInt) {
+TEST_F(WgslGeneratorImplTest_Constructor, UInt) {
     WrapInFunction(Expr(56779_u));
 
     GeneratorImpl& gen = Build();
@@ -51,7 +51,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_F32) {
+TEST_F(WgslGeneratorImplTest_Constructor, F32) {
     // Use a number close to 1<<30 but whose decimal representation ends in 0.
     WrapInFunction(Expr(f32((1 << 30) - 4)));
 
@@ -61,7 +61,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_F16) {
+TEST_F(WgslGeneratorImplTest_Constructor, F16) {
     Enable(builtin::Extension::kF16);
 
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
@@ -73,7 +73,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("32752.0h"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_F32) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_F32) {
     WrapInFunction(Call<f32>(Expr(-1.2e-5_f)));
 
     GeneratorImpl& gen = Build();
@@ -82,7 +82,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("f32(-0.000012f)"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_F16) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(Call<f16>(Expr(-1.2e-5_h)));
@@ -93,7 +93,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("f16(-1.19805336e-05h)"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Bool) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_Bool) {
     WrapInFunction(Call<bool>(true));
 
     GeneratorImpl& gen = Build();
@@ -102,7 +102,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Int) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_Int) {
     WrapInFunction(Call<i32>(-12345_i));
 
     GeneratorImpl& gen = Build();
@@ -111,7 +111,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("i32(-12345i)"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Uint) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_Uint) {
     WrapInFunction(Call<u32>(12345_u));
 
     GeneratorImpl& gen = Build();
@@ -120,7 +120,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("u32(12345u)"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Vec_F32) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_Vec_F32) {
     WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
 
     GeneratorImpl& gen = Build();
@@ -129,7 +129,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("vec3<f32>(1.0f, 2.0f, 3.0f)"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Vec_F16) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_Vec_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
@@ -140,7 +140,7 @@
     EXPECT_THAT(gen.result(), HasSubstr("vec3<f16>(1.0h, 2.0h, 3.0h)"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Mat_F32) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_Mat_F32) {
     WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
 
     GeneratorImpl& gen = Build();
@@ -150,7 +150,7 @@
                                         "vec3<f32>(3.0f, 4.0f, 5.0f))"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Mat_F16) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_Mat_F16) {
     Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
@@ -162,7 +162,7 @@
                                         "vec3<f16>(3.0h, 4.0h, 5.0h))"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Array) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_Array) {
     WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
                         vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
 
@@ -174,7 +174,7 @@
                           "vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(7.0f, 8.0f, 9.0f))"));
 }
 
-TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_ImplicitArray) {
+TEST_F(WgslGeneratorImplTest_Constructor, Type_ImplicitArray) {
     WrapInFunction(Call(ty.array<Infer>(), vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f),
                         vec3<f32>(7_f, 8_f, 9_f)));
 
diff --git a/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc b/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
index b996312..301bff4 100644
--- a/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
@@ -20,7 +20,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_DiagnosticDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
+    DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
 
     GeneratorImpl& gen = Build();
 
@@ -31,7 +31,8 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_DiagnosticAttribute) {
-    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
+    auto* attr =
+        DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/wgsl/generator_impl_function_test.cc b/src/tint/writer/wgsl/generator_impl_function_test.cc
index 34e26b4..b49d690 100644
--- a/src/tint/writer/wgsl/generator_impl_function_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_function_test.cc
@@ -15,6 +15,7 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/ast/workgroup_attribute.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/writer/wgsl/test_helper.h"
 
 using namespace tint::number_suffixes;  // NOLINT
@@ -85,6 +86,27 @@
 )");
 }
 
+TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_MustUse) {
+    auto* func = Func("my_func", utils::Empty, ty.i32(),
+                      utils::Vector{
+                          Return(1_i),
+                      },
+                      utils::Vector{
+                          MustUse(),
+                      });
+
+    GeneratorImpl& gen = Build();
+
+    gen.increment_indent();
+
+    ASSERT_TRUE(gen.EmitFunction(func));
+    EXPECT_EQ(gen.result(), R"(  @must_use
+  fn my_func() -> i32 {
+    return 1i;
+  }
+)");
+}
+
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize_WithIdent) {
     GlobalConst("height", ty.i32(), Expr(2_i));
     auto* func = Func("my_func", utils::Empty, ty.void_(),
@@ -179,7 +201,7 @@
                                     Member("d", ty.f32()),
                                 });
 
-    GlobalVar("data", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    GlobalVar("data", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
               Binding(0_a), Group(0_a));
 
     {
diff --git a/src/tint/writer/wgsl/generator_impl_global_decl_test.cc b/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
index 5654ebe..cef2c74 100644
--- a/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
@@ -29,7 +29,7 @@
     auto* func_var = Var("a", ty.f32());
     WrapInFunction(func_var);
 
-    GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
@@ -46,7 +46,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
-    GlobalVar("a0", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a0", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* s0 = Structure("S0", utils::Vector{
                                    Member("a", ty.i32()),
@@ -58,7 +58,7 @@
          },
          utils::Empty);
 
-    GlobalVar("a1", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("a1", ty.f32(), builtin::AddressSpace::kPrivate);
 
     auto* s1 = Structure("S1", utils::Vector{
                                    Member("a", ty.i32()),
diff --git a/src/tint/writer/wgsl/generator_impl_identifier_test.cc b/src/tint/writer/wgsl/generator_impl_identifier_test.cc
index e0b167f..7b60b63 100644
--- a/src/tint/writer/wgsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_identifier_test.cc
@@ -20,7 +20,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitIdentifierExpression_Single) {
-    GlobalVar("glsl", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("glsl", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* i = Expr("glsl");
     WrapInFunction(i);
 
diff --git a/src/tint/writer/wgsl/generator_impl_if_test.cc b/src/tint/writer/wgsl/generator_impl_if_test.cc
index 0831f89..8b9d443 100644
--- a/src/tint/writer/wgsl/generator_impl_if_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_if_test.cc
@@ -20,7 +20,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_If) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* cond = Expr("cond");
     auto* body = Block(Return());
@@ -39,8 +39,8 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithElseIf) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("else_cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("else_cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_cond = Expr("else_cond");
     auto* else_body = Block(Return());
@@ -64,7 +64,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithElse) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_body = Block(Return());
 
@@ -87,8 +87,8 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithMultiple) {
-    GlobalVar("cond", ty.bool_(), type::AddressSpace::kPrivate);
-    GlobalVar("else_cond", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.bool_(), builtin::AddressSpace::kPrivate);
+    GlobalVar("else_cond", ty.bool_(), builtin::AddressSpace::kPrivate);
 
     auto* else_cond = Expr("else_cond");
 
diff --git a/src/tint/writer/wgsl/generator_impl_loop_test.cc b/src/tint/writer/wgsl/generator_impl_loop_test.cc
index 46dbbdb..62910fc 100644
--- a/src/tint/writer/wgsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_loop_test.cc
@@ -96,7 +96,7 @@
     // for({ignore(1i); ignore(2i);}; ; ) {
     //   return;
     // }
-    GlobalVar("a", ty.atomic<i32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic<i32>(), builtin::AddressSpace::kWorkgroup);
     auto* multi_stmt = Block(Ignore(1_i), Ignore(2_i));
     auto* f = For(multi_stmt, nullptr, nullptr, Block(Return()));
     WrapInFunction(f);
@@ -160,7 +160,7 @@
     //   return;
     // }
 
-    GlobalVar("a", ty.atomic<i32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic<i32>(), builtin::AddressSpace::kWorkgroup);
     auto* multi_stmt = Block(Ignore(1_i), Ignore(2_i));
     auto* f = For(nullptr, nullptr, multi_stmt, Block(Return()));
     WrapInFunction(f);
@@ -203,7 +203,7 @@
     // for({ ignore(1i); ignore(2i); }; true; { ignore(3i); ignore(4i); }) {
     //   return;
     // }
-    GlobalVar("a", ty.atomic<i32>(), type::AddressSpace::kWorkgroup);
+    GlobalVar("a", ty.atomic<i32>(), builtin::AddressSpace::kWorkgroup);
     auto* multi_stmt_a = Block(Ignore(1_i), Ignore(2_i));
     auto* multi_stmt_b = Block(Ignore(3_i), Ignore(4_i));
     auto* f = For(multi_stmt_a, Expr(true), multi_stmt_b, Block(Return()));
diff --git a/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc b/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
index 5f7ebb5..208be35 100644
--- a/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
@@ -21,7 +21,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) {
     auto* s = Structure("Data", utils::Vector{Member("mem", ty.f32())});
-    GlobalVar("str", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("str", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     auto* expr = MemberAccessor("str", "mem");
     WrapInFunction(expr);
@@ -35,7 +35,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor_OfDref) {
     auto* s = Structure("Data", utils::Vector{Member("mem", ty.f32())});
-    GlobalVar("str", ty.Of(s), type::AddressSpace::kPrivate);
+    GlobalVar("str", ty.Of(s), builtin::AddressSpace::kPrivate);
 
     auto* p = Let("p", AddressOf("str"));
     auto* expr = MemberAccessor(Deref("p"), "mem");
diff --git a/src/tint/writer/wgsl/generator_impl_switch_test.cc b/src/tint/writer/wgsl/generator_impl_switch_test.cc
index 24dbae1..d16808a 100644
--- a/src/tint/writer/wgsl/generator_impl_switch_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_switch_test.cc
@@ -22,7 +22,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Switch) {
-    GlobalVar("cond", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* def_body = Block(create<ast::BreakStatement>());
     auto* def = Case(DefaultCaseSelector(), def_body);
@@ -56,7 +56,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Switch_MixedDefault) {
-    GlobalVar("cond", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("cond", ty.i32(), builtin::AddressSpace::kPrivate);
 
     auto* def_body = Block(create<ast::BreakStatement>());
     auto* def = Case(utils::Vector{CaseSelector(5_i), DefaultCaseSelector()}, def_body);
diff --git a/src/tint/writer/wgsl/generator_impl_type_test.cc b/src/tint/writer/wgsl/generator_impl_type_test.cc
index 4f8740c..422b711 100644
--- a/src/tint/writer/wgsl/generator_impl_type_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_type_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/type/depth_texture.h"
 #include "src/tint/type/multisampled_texture.h"
 #include "src/tint/type/sampled_texture.h"
@@ -132,7 +133,8 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
-    auto type = Alias("make_type_reachable", ty.pointer<f32>(type::AddressSpace::kWorkgroup))->type;
+    auto type =
+        Alias("make_type_reachable", ty.pointer<f32>(builtin::AddressSpace::kWorkgroup))->type;
 
     GeneratorImpl& gen = Build();
 
@@ -143,7 +145,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitType_PointerAccessMode) {
     auto type = Alias("make_type_reachable",
-                      ty.pointer<f32>(type::AddressSpace::kStorage, type::Access::kReadWrite))
+                      ty.pointer<f32>(builtin::AddressSpace::kStorage, builtin::Access::kReadWrite))
                     ->type;
 
     GeneratorImpl& gen = Build();
@@ -439,9 +441,9 @@
                                                      "texture_multisampled_2d"}));
 
 struct StorageTextureData {
-    type::TexelFormat fmt;
+    builtin::TexelFormat fmt;
     type::TextureDimension dim;
-    type::Access access;
+    builtin::Access access;
     const char* name;
 };
 inline std::ostream& operator<<(std::ostream& out, StorageTextureData data) {
@@ -465,17 +467,17 @@
     WgslGeneratorImplTest,
     WgslGenerator_StorageTextureTest,
     testing::Values(
-        StorageTextureData{type::TexelFormat::kRgba8Sint, type::TextureDimension::k1d,
-                           type::Access::kWrite, "texture_storage_1d<rgba8sint, write>"},
-        StorageTextureData{type::TexelFormat::kRgba8Sint, type::TextureDimension::k2d,
-                           type::Access::kWrite, "texture_storage_2d<rgba8sint, write>"},
-        StorageTextureData{type::TexelFormat::kRgba8Sint, type::TextureDimension::k2dArray,
-                           type::Access::kWrite, "texture_storage_2d_array<rgba8sint, write>"},
-        StorageTextureData{type::TexelFormat::kRgba8Sint, type::TextureDimension::k3d,
-                           type::Access::kWrite, "texture_storage_3d<rgba8sint, write>"}));
+        StorageTextureData{builtin::TexelFormat::kRgba8Sint, type::TextureDimension::k1d,
+                           builtin::Access::kWrite, "texture_storage_1d<rgba8sint, write>"},
+        StorageTextureData{builtin::TexelFormat::kRgba8Sint, type::TextureDimension::k2d,
+                           builtin::Access::kWrite, "texture_storage_2d<rgba8sint, write>"},
+        StorageTextureData{builtin::TexelFormat::kRgba8Sint, type::TextureDimension::k2dArray,
+                           builtin::Access::kWrite, "texture_storage_2d_array<rgba8sint, write>"},
+        StorageTextureData{builtin::TexelFormat::kRgba8Sint, type::TextureDimension::k3d,
+                           builtin::Access::kWrite, "texture_storage_3d<rgba8sint, write>"}));
 
 struct ImageFormatData {
-    type::TexelFormat fmt;
+    builtin::TexelFormat fmt;
     const char* name;
 };
 inline std::ostream& operator<<(std::ostream& out, ImageFormatData data) {
@@ -496,22 +498,22 @@
 INSTANTIATE_TEST_SUITE_P(
     WgslGeneratorImplTest,
     WgslGenerator_ImageFormatTest,
-    testing::Values(ImageFormatData{type::TexelFormat::kR32Uint, "r32uint"},
-                    ImageFormatData{type::TexelFormat::kR32Sint, "r32sint"},
-                    ImageFormatData{type::TexelFormat::kR32Float, "r32float"},
-                    ImageFormatData{type::TexelFormat::kRgba8Unorm, "rgba8unorm"},
-                    ImageFormatData{type::TexelFormat::kRgba8Snorm, "rgba8snorm"},
-                    ImageFormatData{type::TexelFormat::kRgba8Uint, "rgba8uint"},
-                    ImageFormatData{type::TexelFormat::kRgba8Sint, "rgba8sint"},
-                    ImageFormatData{type::TexelFormat::kRg32Uint, "rg32uint"},
-                    ImageFormatData{type::TexelFormat::kRg32Sint, "rg32sint"},
-                    ImageFormatData{type::TexelFormat::kRg32Float, "rg32float"},
-                    ImageFormatData{type::TexelFormat::kRgba16Uint, "rgba16uint"},
-                    ImageFormatData{type::TexelFormat::kRgba16Sint, "rgba16sint"},
-                    ImageFormatData{type::TexelFormat::kRgba16Float, "rgba16float"},
-                    ImageFormatData{type::TexelFormat::kRgba32Uint, "rgba32uint"},
-                    ImageFormatData{type::TexelFormat::kRgba32Sint, "rgba32sint"},
-                    ImageFormatData{type::TexelFormat::kRgba32Float, "rgba32float"}));
+    testing::Values(ImageFormatData{builtin::TexelFormat::kR32Uint, "r32uint"},
+                    ImageFormatData{builtin::TexelFormat::kR32Sint, "r32sint"},
+                    ImageFormatData{builtin::TexelFormat::kR32Float, "r32float"},
+                    ImageFormatData{builtin::TexelFormat::kRgba8Unorm, "rgba8unorm"},
+                    ImageFormatData{builtin::TexelFormat::kRgba8Snorm, "rgba8snorm"},
+                    ImageFormatData{builtin::TexelFormat::kRgba8Uint, "rgba8uint"},
+                    ImageFormatData{builtin::TexelFormat::kRgba8Sint, "rgba8sint"},
+                    ImageFormatData{builtin::TexelFormat::kRg32Uint, "rg32uint"},
+                    ImageFormatData{builtin::TexelFormat::kRg32Sint, "rg32sint"},
+                    ImageFormatData{builtin::TexelFormat::kRg32Float, "rg32float"},
+                    ImageFormatData{builtin::TexelFormat::kRgba16Uint, "rgba16uint"},
+                    ImageFormatData{builtin::TexelFormat::kRgba16Sint, "rgba16sint"},
+                    ImageFormatData{builtin::TexelFormat::kRgba16Float, "rgba16float"},
+                    ImageFormatData{builtin::TexelFormat::kRgba32Uint, "rgba32uint"},
+                    ImageFormatData{builtin::TexelFormat::kRgba32Sint, "rgba32sint"},
+                    ImageFormatData{builtin::TexelFormat::kRgba32Float, "rgba32float"}));
 
 TEST_F(WgslGeneratorImplTest, EmitType_Sampler) {
     auto sampler = ty.sampler(type::SamplerKind::kSampler);
diff --git a/src/tint/writer/wgsl/generator_impl_unary_op_test.cc b/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
index 544e1e3..a9cd10c 100644
--- a/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
@@ -20,7 +20,7 @@
 using WgslUnaryOpTest = TestHelper;
 
 TEST_F(WgslUnaryOpTest, AddressOf) {
-    GlobalVar("expr", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
     WrapInFunction(op);
 
@@ -32,7 +32,7 @@
 }
 
 TEST_F(WgslUnaryOpTest, Complement) {
-    GlobalVar("expr", ty.u32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.u32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
     WrapInFunction(op);
 
@@ -44,7 +44,7 @@
 }
 
 TEST_F(WgslUnaryOpTest, Indirection) {
-    GlobalVar("G", ty.f32(), type::AddressSpace::kPrivate);
+    GlobalVar("G", ty.f32(), builtin::AddressSpace::kPrivate);
     auto* p = Let("expr", create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
     WrapInFunction(p, op);
@@ -57,7 +57,7 @@
 }
 
 TEST_F(WgslUnaryOpTest, Not) {
-    GlobalVar("expr", ty.bool_(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.bool_(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
     WrapInFunction(op);
 
@@ -69,7 +69,7 @@
 }
 
 TEST_F(WgslUnaryOpTest, Negation) {
-    GlobalVar("expr", ty.i32(), type::AddressSpace::kPrivate);
+    GlobalVar("expr", ty.i32(), builtin::AddressSpace::kPrivate);
     auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
     WrapInFunction(op);
 
diff --git a/src/tint/writer/wgsl/generator_impl_variable_test.cc b/src/tint/writer/wgsl/generator_impl_variable_test.cc
index 3d39ce9..5c9506f 100644
--- a/src/tint/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_variable_test.cc
@@ -22,7 +22,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitVariable) {
-    auto* v = GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
@@ -32,7 +32,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_AddressSpace) {
-    auto* v = GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate);
+    auto* v = GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate);
 
     GeneratorImpl& gen = Build();
 
@@ -43,7 +43,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Read) {
     auto* s = Structure("S", utils::Vector{Member("a", ty.i32())});
-    auto* v = GlobalVar("a", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead,
+    auto* v = GlobalVar("a", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead,
                         Binding(0_a), Group(0_a));
 
     GeneratorImpl& gen = Build();
@@ -55,7 +55,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Access_ReadWrite) {
     auto* s = Structure("S", utils::Vector{Member("a", ty.i32())});
-    auto* v = GlobalVar("a", ty.Of(s), type::AddressSpace::kStorage, type::Access::kReadWrite,
+    auto* v = GlobalVar("a", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                         Binding(0_a), Group(0_a));
 
     GeneratorImpl& gen = Build();
@@ -76,7 +76,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Initializer) {
-    auto* v = GlobalVar("a", ty.f32(), type::AddressSpace::kPrivate, Expr(1_f));
+    auto* v = GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate, Expr(1_f));
 
     GeneratorImpl& gen = Build();