Import Tint changes from Dawn

Changes:
  - 643f2aad43055f2a2f8576c2ef4fbea958317584 tint/reader/wgsl: Remove type keywords by Ben Clayton <bclayton@google.com>
  - a1bda83c424f296691032f97eaca888bbe137b9d spirv-reader: don't hoist opaque objects by David Neto <dneto@google.com>
  - a0e96b5831fe0e01ee991f1e06f90f19075a1660 Rolling 8 dependencies by Austin Eng <enga@chromium.org>
  - e4039c76c731b4e41181ea07ef3afe1ed9400aab Move the Extension builtin to the builtin/ folder. by dan sinclair <dsinclair@chromium.org>
  - 6392579ee1f146e346ca308abc98d76da60a83ae Move BuiltinValue to builtin/ by dan sinclair <dsinclair@chromium.org>
GitOrigin-RevId: 643f2aad43055f2a2f8576c2ef4fbea958317584
Change-Id: I680df7feb29421a9e2c6239df4bc722d1a14787b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/120388
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 f0ca1dd..dd679c7 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -277,6 +277,7 @@
   deps = [
     ":libtint_ast_hdrs",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_constant_src",
     ":libtint_sem_src",
     ":libtint_text_src",
@@ -310,6 +311,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_program_src",
     ":libtint_sem_src",
     ":libtint_type_src",
@@ -431,6 +433,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_program_src",
     ":libtint_sem_src",
     ":libtint_text_src",
@@ -452,7 +455,6 @@
     "ast/break_if_statement.h",
     "ast/break_statement.h",
     "ast/builtin_attribute.h",
-    "ast/builtin_value.h",
     "ast/call_expression.h",
     "ast/call_statement.h",
     "ast/case_selector.h",
@@ -468,7 +470,6 @@
     "ast/discard_statement.h",
     "ast/enable.h",
     "ast/expression.h",
-    "ast/extension.h",
     "ast/float_literal_expression.h",
     "ast/for_loop_statement.h",
     "ast/function.h",
@@ -519,6 +520,7 @@
   ]
   deps = [
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_clone_context_hdrs",
     ":libtint_type_src",
   ]
@@ -538,7 +540,6 @@
     "ast/break_if_statement.cc",
     "ast/break_statement.cc",
     "ast/builtin_attribute.cc",
-    "ast/builtin_value.cc",
     "ast/call_expression.cc",
     "ast/call_statement.cc",
     "ast/case_selector.cc",
@@ -554,7 +555,6 @@
     "ast/discard_statement.cc",
     "ast/enable.cc",
     "ast/expression.cc",
-    "ast/extension.cc",
     "ast/float_literal_expression.cc",
     "ast/for_loop_statement.cc",
     "ast/function.cc",
@@ -685,11 +685,22 @@
   deps = [
     ":libtint_ast_hdrs",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_constant_src",
     ":libtint_type_src",
   ]
 }
 
+libtint_source_set("libtint_builtins_src") {
+  sources = [
+    "builtin/builtin_value.cc",
+    "builtin/builtin_value.h",
+    "builtin/extension.cc",
+    "builtin/extension.h",
+  ]
+  deps = [ ":libtint_base_src" ]
+}
+
 libtint_source_set("libtint_type_src") {
   sources = [
     "type/abstract_float.cc",
@@ -826,6 +837,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_program_src",
     ":libtint_reader_src",
     ":libtint_sem_src",
@@ -861,6 +873,7 @@
   deps = [
     ":libtint_ast_src",
     ":libtint_base_src",
+    ":libtint_builtins_src",
     ":libtint_inspector_src",
     ":libtint_program_src",
     ":libtint_sem_src",
@@ -1212,7 +1225,6 @@
       "ast/builtin_attribute_test.cc",
       "ast/builtin_texture_helper_test.cc",
       "ast/builtin_texture_helper_test.h",
-      "ast/builtin_value_test.cc",
       "ast/call_expression_test.cc",
       "ast/call_statement_test.cc",
       "ast/case_selector_test.cc",
@@ -1225,7 +1237,6 @@
       "ast/diagnostic_directive_test.cc",
       "ast/discard_statement_test.cc",
       "ast/enable_test.cc",
-      "ast/extension_test.cc",
       "ast/float_literal_expression_test.cc",
       "ast/for_loop_statement_test.cc",
       "ast/function_test.cc",
@@ -1274,6 +1285,14 @@
     }
   }
 
+  tint_unittests_source_set("tint_unittests_builtins_src") {
+    sources = [
+      "builtin/builtin_value_test.cc",
+      "builtin/extension_test.cc",
+    ]
+    deps = [ ":libtint_builtins_src" ]
+  }
+
   tint_unittests_source_set("tint_unittests_diagnostic_src") {
     sources = [
       "diagnostic/diagnostic_test.cc",
@@ -1361,6 +1380,7 @@
     ]
     deps = [
       ":libtint_base_src",
+      ":libtint_builtins_src",
       ":libtint_transform_src",
       ":tint_unittests_ast_src",
     ]
@@ -1614,6 +1634,7 @@
 
     deps = [
       ":libtint_base_src",
+      ":libtint_builtins_src",
       ":libtint_spv_writer_src",
       ":tint_unittests_ast_src",
       "${tint_spirv_tools_dir}/:spvtools",
@@ -1632,14 +1653,12 @@
       "reader/wgsl/parser_impl_break_stmt_test.cc",
       "reader/wgsl/parser_impl_bug_cases_test.cc",
       "reader/wgsl/parser_impl_call_stmt_test.cc",
-      "reader/wgsl/parser_impl_callable_test.cc",
       "reader/wgsl/parser_impl_case_body_test.cc",
       "reader/wgsl/parser_impl_compound_stmt_test.cc",
       "reader/wgsl/parser_impl_const_literal_test.cc",
       "reader/wgsl/parser_impl_continue_stmt_test.cc",
       "reader/wgsl/parser_impl_continuing_stmt_test.cc",
       "reader/wgsl/parser_impl_core_lhs_expression_test.cc",
-      "reader/wgsl/parser_impl_depth_texture_test.cc",
       "reader/wgsl/parser_impl_diagnostic_attribute_test.cc",
       "reader/wgsl/parser_impl_diagnostic_control_test.cc",
       "reader/wgsl/parser_impl_diagnostic_directive_test.cc",
@@ -1648,7 +1667,6 @@
       "reader/wgsl/parser_impl_error_msg_test.cc",
       "reader/wgsl/parser_impl_error_resync_test.cc",
       "reader/wgsl/parser_impl_expression_test.cc",
-      "reader/wgsl/parser_impl_external_texture_test.cc",
       "reader/wgsl/parser_impl_for_stmt_test.cc",
       "reader/wgsl/parser_impl_function_attribute_list_test.cc",
       "reader/wgsl/parser_impl_function_attribute_test.cc",
@@ -1668,13 +1686,10 @@
       "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_sampled_texture_test.cc",
-      "reader/wgsl/parser_impl_sampler_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_storage_texture_test.cc",
       "reader/wgsl/parser_impl_struct_attribute_decl_test.cc",
       "reader/wgsl/parser_impl_struct_body_decl_test.cc",
       "reader/wgsl/parser_impl_struct_decl_test.cc",
@@ -1686,11 +1701,8 @@
       "reader/wgsl/parser_impl_test.cc",
       "reader/wgsl/parser_impl_test_helper.cc",
       "reader/wgsl/parser_impl_test_helper.h",
-      "reader/wgsl/parser_impl_texel_format_test.cc",
-      "reader/wgsl/parser_impl_texture_sampler_test.cc",
       "reader/wgsl/parser_impl_type_alias_test.cc",
       "reader/wgsl/parser_impl_type_decl_test.cc",
-      "reader/wgsl/parser_impl_type_decl_without_ident_test.cc",
       "reader/wgsl/parser_impl_unary_expression_test.cc",
       "reader/wgsl/parser_impl_variable_attribute_list_test.cc",
       "reader/wgsl/parser_impl_variable_attribute_test.cc",
@@ -1698,7 +1710,6 @@
       "reader/wgsl/parser_impl_variable_ident_decl_test.cc",
       "reader/wgsl/parser_impl_variable_qualifier_test.cc",
       "reader/wgsl/parser_impl_variable_stmt_test.cc",
-      "reader/wgsl/parser_impl_vec_mat_prefix_test.cc",
       "reader/wgsl/parser_impl_while_stmt_test.cc",
       "reader/wgsl/parser_test.cc",
       "reader/wgsl/token_test.cc",
@@ -1931,6 +1942,7 @@
       ":libtint_wgsl_writer_src",
       ":tint_unittests_ast_src",
       ":tint_unittests_base_src",
+      ":tint_unittests_builtins_src",
       ":tint_unittests_constant_src",
       ":tint_unittests_core_src",
       ":tint_unittests_demangler_src",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 868bce5..67ca5e9 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -548,9 +548,9 @@
   writer/writer.h
 )
 
-tint_generated(ast/builtin_value BENCH TEST)
+tint_generated(builtin/builtin_value BENCH TEST)
+tint_generated(builtin/extension BENCH TEST)
 tint_generated(ast/diagnostic_control BENCH TEST)
-tint_generated(ast/extension BENCH TEST)
 tint_generated(ast/interpolate_attribute BENCH TEST)
 tint_generated(resolver/init_conv_intrinsic)
 tint_generated(sem/builtin_type)
@@ -1055,14 +1055,12 @@
       reader/wgsl/parser_impl_break_stmt_test.cc
       reader/wgsl/parser_impl_bug_cases_test.cc
       reader/wgsl/parser_impl_call_stmt_test.cc
-      reader/wgsl/parser_impl_callable_test.cc
       reader/wgsl/parser_impl_case_body_test.cc
       reader/wgsl/parser_impl_compound_stmt_test.cc
       reader/wgsl/parser_impl_const_literal_test.cc
       reader/wgsl/parser_impl_continue_stmt_test.cc
       reader/wgsl/parser_impl_continuing_stmt_test.cc
       reader/wgsl/parser_impl_core_lhs_expression_test.cc
-      reader/wgsl/parser_impl_depth_texture_test.cc
       reader/wgsl/parser_impl_diagnostic_attribute_test.cc
       reader/wgsl/parser_impl_diagnostic_control_test.cc
       reader/wgsl/parser_impl_diagnostic_directive_test.cc
@@ -1071,7 +1069,6 @@
       reader/wgsl/parser_impl_error_msg_test.cc
       reader/wgsl/parser_impl_error_resync_test.cc
       reader/wgsl/parser_impl_expression_test.cc
-      reader/wgsl/parser_impl_external_texture_test.cc
       reader/wgsl/parser_impl_for_stmt_test.cc
       reader/wgsl/parser_impl_function_decl_test.cc
       reader/wgsl/parser_impl_function_attribute_list_test.cc
@@ -1091,14 +1088,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_sampled_texture_test.cc
-      reader/wgsl/parser_impl_sampler_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_storage_texture_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
@@ -1110,11 +1104,8 @@
       reader/wgsl/parser_impl_test.cc
       reader/wgsl/parser_impl_test_helper.cc
       reader/wgsl/parser_impl_test_helper.h
-      reader/wgsl/parser_impl_texel_format_test.cc
-      reader/wgsl/parser_impl_texture_sampler_test.cc
       reader/wgsl/parser_impl_type_alias_test.cc
       reader/wgsl/parser_impl_type_decl_test.cc
-      reader/wgsl/parser_impl_type_decl_without_ident_test.cc
       reader/wgsl/parser_impl_unary_expression_test.cc
       reader/wgsl/parser_impl_variable_decl_test.cc
       reader/wgsl/parser_impl_variable_attribute_list_test.cc
@@ -1122,7 +1113,6 @@
       reader/wgsl/parser_impl_variable_ident_decl_test.cc
       reader/wgsl/parser_impl_variable_stmt_test.cc
       reader/wgsl/parser_impl_variable_qualifier_test.cc
-      reader/wgsl/parser_impl_vec_mat_prefix_test.cc
       reader/wgsl/parser_impl_while_stmt_test.cc
       reader/wgsl/token_test.cc
     )
diff --git a/src/tint/ast/builtin_attribute.cc b/src/tint/ast/builtin_attribute.cc
index d5aace0..e3f9d7b 100644
--- a/src/tint/ast/builtin_attribute.cc
+++ b/src/tint/ast/builtin_attribute.cc
@@ -22,7 +22,10 @@
 
 namespace tint::ast {
 
-BuiltinAttribute::BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, BuiltinValue b)
+BuiltinAttribute::BuiltinAttribute(ProgramID pid,
+                                   NodeID nid,
+                                   const Source& src,
+                                   builtin::BuiltinValue b)
     : Base(pid, nid, src), builtin(b) {}
 
 BuiltinAttribute::~BuiltinAttribute() = default;
diff --git a/src/tint/ast/builtin_attribute.h b/src/tint/ast/builtin_attribute.h
index 0aae24b..6f9b156 100644
--- a/src/tint/ast/builtin_attribute.h
+++ b/src/tint/ast/builtin_attribute.h
@@ -18,7 +18,7 @@
 #include <string>
 
 #include "src/tint/ast/attribute.h"
-#include "src/tint/ast/builtin_value.h"
+#include "src/tint/builtin/builtin_value.h"
 
 namespace tint::ast {
 
@@ -30,7 +30,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, BuiltinValue builtin);
+    BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, builtin::BuiltinValue builtin);
     ~BuiltinAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -43,7 +43,7 @@
     const BuiltinAttribute* Clone(CloneContext* ctx) const override;
 
     /// The builtin value
-    const BuiltinValue builtin;
+    const builtin::BuiltinValue builtin;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/builtin_attribute_test.cc b/src/tint/ast/builtin_attribute_test.cc
index dba6997..3421e0f 100644
--- a/src/tint/ast/builtin_attribute_test.cc
+++ b/src/tint/ast/builtin_attribute_test.cc
@@ -20,8 +20,8 @@
 using BuiltinAttributeTest = TestHelper;
 
 TEST_F(BuiltinAttributeTest, Creation) {
-    auto* d = create<BuiltinAttribute>(BuiltinValue::kFragDepth);
-    EXPECT_EQ(BuiltinValue::kFragDepth, d->builtin);
+    auto* d = create<BuiltinAttribute>(builtin::BuiltinValue::kFragDepth);
+    EXPECT_EQ(builtin::BuiltinValue::kFragDepth, d->builtin);
 }
 
 }  // namespace
diff --git a/src/tint/ast/enable.cc b/src/tint/ast/enable.cc
index 896b019..6087a3e 100644
--- a/src/tint/ast/enable.cc
+++ b/src/tint/ast/enable.cc
@@ -20,7 +20,7 @@
 
 namespace tint::ast {
 
-Enable::Enable(ProgramID pid, NodeID nid, const Source& src, Extension ext)
+Enable::Enable(ProgramID pid, NodeID nid, const Source& src, builtin::Extension ext)
     : Base(pid, nid, src), extension(ext) {}
 
 Enable::Enable(Enable&&) = default;
diff --git a/src/tint/ast/enable.h b/src/tint/ast/enable.h
index 4c27113..0c64df9 100644
--- a/src/tint/ast/enable.h
+++ b/src/tint/ast/enable.h
@@ -19,8 +19,8 @@
 #include <utility>
 #include <vector>
 
-#include "src/tint/ast/extension.h"
 #include "src/tint/ast/node.h"
+#include "src/tint/builtin/extension.h"
 
 namespace tint::ast {
 
@@ -36,7 +36,7 @@
     /// @param nid the unique node identifier
     /// @param src the source of this node
     /// @param ext the extension
-    Enable(ProgramID pid, NodeID nid, const Source& src, Extension ext);
+    Enable(ProgramID pid, NodeID nid, const Source& src, builtin::Extension ext);
     /// Move constructor
     Enable(Enable&&);
 
@@ -49,7 +49,7 @@
     const Enable* Clone(CloneContext* ctx) const override;
 
     /// The extension name
-    const Extension extension;
+    const builtin::Extension extension;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/enable_test.cc b/src/tint/ast/enable_test.cc
index e8b6e5c..9215018 100644
--- a/src/tint/ast/enable_test.cc
+++ b/src/tint/ast/enable_test.cc
@@ -22,12 +22,12 @@
 using EnableTest = TestHelper;
 
 TEST_F(EnableTest, Creation) {
-    auto* ext = create<ast::Enable>(Source{{{20, 2}, {20, 5}}}, Extension::kF16);
+    auto* ext = create<ast::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);
     EXPECT_EQ(ext->source.range.end.column, 5u);
-    EXPECT_EQ(ext->extension, Extension::kF16);
+    EXPECT_EQ(ext->extension, builtin::Extension::kF16);
 }
 
 }  // namespace
diff --git a/src/tint/ast/module_test.cc b/src/tint/ast/module_test.cc
index cd03781..24faaee 100644
--- a/src/tint/ast/module_test.cc
+++ b/src/tint/ast/module_test.cc
@@ -135,9 +135,9 @@
 }
 
 TEST_F(ModuleTest, Directives) {
-    auto* enable_1 = Enable(ast::Extension::kF16);
+    auto* enable_1 = Enable(builtin::Extension::kF16);
     auto* diagnostic_1 = DiagnosticDirective(DiagnosticSeverity::kWarning, "foo");
-    auto* enable_2 = Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
+    auto* enable_2 = Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     auto* diagnostic_2 = DiagnosticDirective(DiagnosticSeverity::kOff, "bar");
 
     this->SetResolveOnBuild(false);
diff --git a/src/tint/ast/variable_test.cc b/src/tint/ast/variable_test.cc
index ff97b2f..88bcdc4 100644
--- a/src/tint/ast/variable_test.cc
+++ b/src/tint/ast/variable_test.cc
@@ -93,7 +93,7 @@
 
 TEST_F(VariableTest, WithAttributes) {
     auto* var = Var("my_var", ty.i32(), type::AddressSpace::kFunction, Location(1_u),
-                    Builtin(BuiltinValue::kPosition), Id(1200_u));
+                    Builtin(builtin::BuiltinValue::kPosition), Id(1200_u));
 
     auto& attributes = var->attributes;
     EXPECT_TRUE(ast::HasAttribute<ast::LocationAttribute>(attributes));
diff --git a/src/tint/ast/builtin_value.cc b/src/tint/builtin/builtin_value.cc
similarity index 95%
rename from src/tint/ast/builtin_value.cc
rename to src/tint/builtin/builtin_value.cc
index 0a4439b..740ebcc 100644
--- a/src/tint/ast/builtin_value.cc
+++ b/src/tint/builtin/builtin_value.cc
@@ -15,14 +15,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/builtin_value.cc.tmpl
+//   src/tint/builtin/builtin_value.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/builtin_value.h"
+#include "src/tint/builtin/builtin_value.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 
 /// ParseBuiltinValue parses a BuiltinValue from a string.
 /// @param str the string to parse
@@ -101,4 +101,4 @@
     return out << "<unknown>";
 }
 
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/builtin_value.cc.tmpl b/src/tint/builtin/builtin_value.cc.tmpl
similarity index 84%
rename from src/tint/ast/builtin_value.cc.tmpl
rename to src/tint/builtin/builtin_value.cc.tmpl
index 7340c88..02ba5de 100644
--- a/src/tint/ast/builtin_value.cc.tmpl
+++ b/src/tint/builtin/builtin_value.cc.tmpl
@@ -11,12 +11,12 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "builtin_value") -}}
 
-#include "src/tint/ast/builtin_value.h"
+#include "src/tint/builtin/builtin_value.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 
 {{ Eval "ParseEnum" $enum}}
 
 {{ Eval "EnumOStream" $enum}}
 
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/builtin_value.h b/src/tint/builtin/builtin_value.h
similarity index 89%
rename from src/tint/ast/builtin_value.h
rename to src/tint/builtin/builtin_value.h
index 3a3c786..1d5b4d4 100644
--- a/src/tint/ast/builtin_value.h
+++ b/src/tint/builtin/builtin_value.h
@@ -15,17 +15,17 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/builtin_value.h.tmpl
+//   src/tint/builtin/builtin_value.h.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#ifndef SRC_TINT_AST_BUILTIN_VALUE_H_
-#define SRC_TINT_AST_BUILTIN_VALUE_H_
+#ifndef SRC_TINT_BUILTIN_BUILTIN_VALUE_H_
+#define SRC_TINT_BUILTIN_BUILTIN_VALUE_H_
 
 #include <ostream>
 
-namespace tint::ast {
+namespace tint::builtin {
 
 /// Builtin value defined with `@builtin(<name>)`.
 enum class BuiltinValue {
@@ -64,6 +64,6 @@
     "vertex_index",         "workgroup_id",
 };
 
-}  // namespace tint::ast
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_AST_BUILTIN_VALUE_H_
+#endif  // SRC_TINT_BUILTIN_BUILTIN_VALUE_H_
diff --git a/src/tint/ast/builtin_value.h.tmpl b/src/tint/builtin/builtin_value.h.tmpl
similarity index 76%
rename from src/tint/ast/builtin_value.h.tmpl
rename to src/tint/builtin/builtin_value.h.tmpl
index ea63d56..46e806e 100644
--- a/src/tint/ast/builtin_value.h.tmpl
+++ b/src/tint/builtin/builtin_value.h.tmpl
@@ -11,16 +11,16 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "builtin_value") -}}
 
-#ifndef SRC_TINT_AST_BUILTIN_VALUE_H_
-#define SRC_TINT_AST_BUILTIN_VALUE_H_
+#ifndef SRC_TINT_BUILTIN_BUILTIN_VALUE_H_
+#define SRC_TINT_BUILTIN_BUILTIN_VALUE_H_
 
 #include <ostream>
 
-namespace tint::ast {
+namespace tint::builtin {
 
 /// Builtin value defined with `@builtin(<name>)`.
 {{ Eval "DeclareEnum" $enum}}
 
-}  // namespace tint::ast
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_AST_BUILTIN_VALUE_H_
+#endif  // SRC_TINT_BUILTIN_BUILTIN_VALUE_H_
diff --git a/src/tint/ast/builtin_value_bench.cc b/src/tint/builtin/builtin_value_bench.cc
similarity index 95%
rename from src/tint/ast/builtin_value_bench.cc
rename to src/tint/builtin/builtin_value_bench.cc
index 879b0a5..50d677e 100644
--- a/src/tint/ast/builtin_value_bench.cc
+++ b/src/tint/builtin/builtin_value_bench.cc
@@ -15,18 +15,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/builtin_value_bench.cc.tmpl
+//   src/tint/builtin/builtin_value_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/builtin_value.h"
+#include "src/tint/builtin/builtin_value.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 void BuiltinValueParser(::benchmark::State& state) {
@@ -127,4 +127,4 @@
 BENCHMARK(BuiltinValueParser);
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/builtin_value_bench.cc.tmpl b/src/tint/builtin/builtin_value_bench.cc.tmpl
similarity index 85%
rename from src/tint/ast/builtin_value_bench.cc.tmpl
rename to src/tint/builtin/builtin_value_bench.cc.tmpl
index f50bd20..aa0ee17 100644
--- a/src/tint/ast/builtin_value_bench.cc.tmpl
+++ b/src/tint/builtin/builtin_value_bench.cc.tmpl
@@ -11,16 +11,16 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "builtin_value") -}}
 
-#include "src/tint/ast/builtin_value.h"
+#include "src/tint/builtin/builtin_value.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" $enum }}
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/builtin_value_test.cc b/src/tint/builtin/builtin_value_test.cc
similarity index 95%
rename from src/tint/ast/builtin_value_test.cc
rename to src/tint/builtin/builtin_value_test.cc
index 0ee2206..b245250 100644
--- a/src/tint/ast/builtin_value_test.cc
+++ b/src/tint/builtin/builtin_value_test.cc
@@ -15,19 +15,20 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/builtin_value_test.cc.tmpl
+//   src/tint/builtin/builtin_value_test.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/builtin_value.h"
+#include "src/tint/builtin/builtin_value.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/ast/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 namespace parse_print_tests {
@@ -119,4 +120,4 @@
 }  // namespace parse_print_tests
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/builtin_value_test.cc.tmpl b/src/tint/builtin/builtin_value_test.cc.tmpl
similarity index 82%
rename from src/tint/ast/builtin_value_test.cc.tmpl
rename to src/tint/builtin/builtin_value_test.cc.tmpl
index 213a81b..e629eed 100644
--- a/src/tint/ast/builtin_value_test.cc.tmpl
+++ b/src/tint/builtin/builtin_value_test.cc.tmpl
@@ -11,17 +11,18 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "builtin_value") -}}
 
-#include "src/tint/ast/builtin_value.h"
+#include "src/tint/builtin/builtin_value.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/ast/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "TestParsePrintEnum" $enum}}
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/extension.cc b/src/tint/builtin/extension.cc
similarity index 94%
rename from src/tint/ast/extension.cc
rename to src/tint/builtin/extension.cc
index 31a8083..3d57867 100644
--- a/src/tint/ast/extension.cc
+++ b/src/tint/builtin/extension.cc
@@ -15,14 +15,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/extension.cc.tmpl
+//   src/tint/builtin/extension.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 
 /// ParseExtension parses a Extension from a string.
 /// @param str the string to parse
@@ -64,4 +64,4 @@
     return out << "<unknown>";
 }
 
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/extension.cc.tmpl b/src/tint/builtin/extension.cc.tmpl
similarity index 84%
rename from src/tint/ast/extension.cc.tmpl
rename to src/tint/builtin/extension.cc.tmpl
index e0f319e..5f00264 100644
--- a/src/tint/ast/extension.cc.tmpl
+++ b/src/tint/builtin/extension.cc.tmpl
@@ -11,12 +11,12 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "extension") -}}
 
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 
 {{ Eval "ParseEnum" $enum}}
 
 {{ Eval "EnumOStream" $enum}}
 
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/extension.h b/src/tint/builtin/extension.h
similarity index 89%
rename from src/tint/ast/extension.h
rename to src/tint/builtin/extension.h
index 062e3fc..f0ebeca 100644
--- a/src/tint/ast/extension.h
+++ b/src/tint/builtin/extension.h
@@ -15,19 +15,19 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/extension.h.tmpl
+//   src/tint/builtin/extension.h.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#ifndef SRC_TINT_AST_EXTENSION_H_
-#define SRC_TINT_AST_EXTENSION_H_
+#ifndef SRC_TINT_BUILTIN_EXTENSION_H_
+#define SRC_TINT_BUILTIN_EXTENSION_H_
 
 #include <ostream>
 
 #include "src/tint/utils/unique_vector.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 
 /// An enumerator of WGSL extensions
 /// @see src/tint/intrinsics.def for extension descriptions
@@ -61,6 +61,6 @@
 // A unique vector of extensions
 using Extensions = utils::UniqueVector<Extension, 4>;
 
-}  // namespace tint::ast
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_AST_EXTENSION_H_
+#endif  // SRC_TINT_BUILTIN_EXTENSION_H_
diff --git a/src/tint/ast/extension.h.tmpl b/src/tint/builtin/extension.h.tmpl
similarity index 81%
rename from src/tint/ast/extension.h.tmpl
rename to src/tint/builtin/extension.h.tmpl
index 29feff9..3051ad4 100644
--- a/src/tint/ast/extension.h.tmpl
+++ b/src/tint/builtin/extension.h.tmpl
@@ -11,14 +11,14 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "extension") -}}
 
-#ifndef SRC_TINT_AST_EXTENSION_H_
-#define SRC_TINT_AST_EXTENSION_H_
+#ifndef SRC_TINT_BUILTIN_EXTENSION_H_
+#define SRC_TINT_BUILTIN_EXTENSION_H_
 
 #include <ostream>
 
 #include "src/tint/utils/unique_vector.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 
 /// An enumerator of WGSL extensions
 /// @see src/tint/intrinsics.def for extension descriptions
@@ -27,6 +27,6 @@
 // A unique vector of extensions
 using Extensions = utils::UniqueVector<Extension, 4>;
 
-}  // namespace tint::ast
+}  // namespace tint::builtin
 
-#endif  // SRC_TINT_AST_EXTENSION_H_
+#endif  // SRC_TINT_BUILTIN_EXTENSION_H_
diff --git a/src/tint/ast/extension_bench.cc b/src/tint/builtin/extension_bench.cc
similarity index 94%
rename from src/tint/ast/extension_bench.cc
rename to src/tint/builtin/extension_bench.cc
index 3bf35f6..4619ce2 100644
--- a/src/tint/ast/extension_bench.cc
+++ b/src/tint/builtin/extension_bench.cc
@@ -15,18 +15,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/extension_bench.cc.tmpl
+//   src/tint/builtin/extension_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 void ExtensionParser(::benchmark::State& state) {
@@ -78,4 +78,4 @@
 BENCHMARK(ExtensionParser);
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/extension_bench.cc.tmpl b/src/tint/builtin/extension_bench.cc.tmpl
similarity index 86%
rename from src/tint/ast/extension_bench.cc.tmpl
rename to src/tint/builtin/extension_bench.cc.tmpl
index af3dc95..5019b55 100644
--- a/src/tint/ast/extension_bench.cc.tmpl
+++ b/src/tint/builtin/extension_bench.cc.tmpl
@@ -11,16 +11,16 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "extension") -}}
 
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" $enum }}
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/extension_test.cc b/src/tint/builtin/extension_test.cc
similarity index 94%
rename from src/tint/ast/extension_test.cc
rename to src/tint/builtin/extension_test.cc
index ea08dcc..01eb1ae 100644
--- a/src/tint/ast/extension_test.cc
+++ b/src/tint/builtin/extension_test.cc
@@ -15,19 +15,20 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/extension_test.cc.tmpl
+//   src/tint/builtin/extension_test.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/ast/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 namespace parse_print_tests {
@@ -92,4 +93,4 @@
 }  // namespace parse_print_tests
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/extension_test.cc.tmpl b/src/tint/builtin/extension_test.cc.tmpl
similarity index 83%
rename from src/tint/ast/extension_test.cc.tmpl
rename to src/tint/builtin/extension_test.cc.tmpl
index 8c7a6af..6b735b7 100644
--- a/src/tint/ast/extension_test.cc.tmpl
+++ b/src/tint/builtin/extension_test.cc.tmpl
@@ -11,17 +11,18 @@
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 {{- $enum := (Sem.Enum "extension") -}}
 
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
+
+#include <gtest/gtest.h>
 
 #include <string>
 
-#include "src/tint/ast/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "TestParsePrintEnum" $enum}}
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/cmd/main.cc b/src/tint/cmd/main.cc
index 49037a7..cd46885 100644
--- a/src/tint/cmd/main.cc
+++ b/src/tint/cmd/main.cc
@@ -734,7 +734,7 @@
                 auto enable_list = program->AST().Enables();
                 bool dxc_require_16bit_types = false;
                 for (auto enable : enable_list) {
-                    if (enable->extension == tint::ast::Extension::kF16) {
+                    if (enable->extension == tint::builtin::Extension::kF16) {
                         dxc_require_16bit_types = true;
                         break;
                     }
diff --git a/src/tint/inspector/inspector.cc b/src/tint/inspector/inspector.cc
index 26202e3..40658db 100644
--- a/src/tint/inspector/inspector.cc
+++ b/src/tint/inspector/inspector.cc
@@ -19,7 +19,6 @@
 
 #include "src/tint/ast/bool_literal_expression.h"
 #include "src/tint/ast/call_expression.h"
-#include "src/tint/ast/extension.h"
 #include "src/tint/ast/float_literal_expression.h"
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/ast/identifier.h"
@@ -29,6 +28,7 @@
 #include "src/tint/ast/module.h"
 #include "src/tint/ast/override.h"
 #include "src/tint/ast/var.h"
+#include "src/tint/builtin/extension.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/module.h"
@@ -216,15 +216,15 @@
                                     param->Location(), entry_point.input_variables);
 
         entry_point.input_position_used |= ContainsBuiltin(
-            ast::BuiltinValue::kPosition, param->Type(), param->Declaration()->attributes);
+            builtin::BuiltinValue::kPosition, param->Type(), param->Declaration()->attributes);
         entry_point.front_facing_used |= ContainsBuiltin(
-            ast::BuiltinValue::kFrontFacing, param->Type(), param->Declaration()->attributes);
+            builtin::BuiltinValue::kFrontFacing, param->Type(), param->Declaration()->attributes);
         entry_point.sample_index_used |= ContainsBuiltin(
-            ast::BuiltinValue::kSampleIndex, param->Type(), param->Declaration()->attributes);
+            builtin::BuiltinValue::kSampleIndex, param->Type(), param->Declaration()->attributes);
         entry_point.input_sample_mask_used |= ContainsBuiltin(
-            ast::BuiltinValue::kSampleMask, param->Type(), param->Declaration()->attributes);
+            builtin::BuiltinValue::kSampleMask, param->Type(), param->Declaration()->attributes);
         entry_point.num_workgroups_used |= ContainsBuiltin(
-            ast::BuiltinValue::kNumWorkgroups, param->Type(), param->Declaration()->attributes);
+            builtin::BuiltinValue::kNumWorkgroups, param->Type(), param->Declaration()->attributes);
     }
 
     if (!sem->ReturnType()->Is<type::Void>()) {
@@ -232,9 +232,9 @@
                                     sem->ReturnLocation(), entry_point.output_variables);
 
         entry_point.output_sample_mask_used = ContainsBuiltin(
-            ast::BuiltinValue::kSampleMask, sem->ReturnType(), func->return_type_attributes);
+            builtin::BuiltinValue::kSampleMask, sem->ReturnType(), func->return_type_attributes);
         entry_point.frag_depth_used = ContainsBuiltin(
-            ast::BuiltinValue::kFragDepth, sem->ReturnType(), func->return_type_attributes);
+            builtin::BuiltinValue::kFragDepth, sem->ReturnType(), func->return_type_attributes);
     }
 
     for (auto* var : sem->TransitivelyReferencedGlobals()) {
@@ -681,7 +681,7 @@
     variables.push_back(stage_variable);
 }
 
-bool Inspector::ContainsBuiltin(ast::BuiltinValue builtin,
+bool Inspector::ContainsBuiltin(builtin::BuiltinValue builtin,
                                 const type::Type* type,
                                 utils::VectorRef<const ast::Attribute*> attributes) const {
     auto* unwrapped_type = type->UnwrapRef();
diff --git a/src/tint/inspector/inspector.h b/src/tint/inspector/inspector.h
index b16fadf..5854125 100644
--- a/src/tint/inspector/inspector.h
+++ b/src/tint/inspector/inspector.h
@@ -183,7 +183,7 @@
     /// Recursively determine if the type contains builtin.
     /// If `type` is a struct, recurse into members to check for the attribute.
     /// Otherwise, check `attributes` for the attribute.
-    bool ContainsBuiltin(ast::BuiltinValue builtin,
+    bool ContainsBuiltin(builtin::BuiltinValue builtin,
                          const type::Type* type,
                          utils::VectorRef<const ast::Attribute*> attributes) const;
 
diff --git a/src/tint/inspector/inspector_test.cc b/src/tint/inspector/inspector_test.cc
index fe4cba1..743f878 100644
--- a/src/tint/inspector/inspector_test.cc
+++ b/src/tint/inspector/inspector_test.cc
@@ -289,7 +289,7 @@
     std::function<ast::Type()> tint_type = GetTypeFunction(component, composition);
 
     if (component == ComponentType::kF16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
     }
 
     auto* in_var = Param("in_var", tint_type(),
@@ -464,7 +464,7 @@
 TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables) {
     auto* in_var0 = Param("in_var0", ty.u32(),
                           utils::Vector{
-                              Builtin(ast::BuiltinValue::kSampleIndex),
+                              Builtin(builtin::BuiltinValue::kSampleIndex),
                           });
     auto* in_var1 = Param("in_var1", ty.f32(),
                           utils::Vector{
@@ -478,7 +478,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kFragDepth),
+             Builtin(builtin::BuiltinValue::kFragDepth),
          });
     Inspector& inspector = Build();
 
@@ -1049,7 +1049,7 @@
 TEST_F(InspectorGetEntryPointTest, InputSampleMaskSimpleReferenced) {
     auto* in_var = Param("in_var", ty.u32(),
                          utils::Vector{
-                             Builtin(ast::BuiltinValue::kSampleMask),
+                             Builtin(builtin::BuiltinValue::kSampleMask),
                          });
     Func("ep_func", utils::Vector{in_var}, ty.void_(),
          utils::Vector{
@@ -1069,7 +1069,8 @@
 
 TEST_F(InspectorGetEntryPointTest, InputSampleMaskStructReferenced) {
     utils::Vector members{
-        Member("inner_position", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleMask)}),
+        Member("inner_position", ty.u32(),
+               utils::Vector{Builtin(builtin::BuiltinValue::kSampleMask)}),
     };
 
     Structure("in_struct", members);
@@ -1097,7 +1098,7 @@
 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskSimpleReferenced) {
     Func("ep_func",
          utils::Vector{
-             Param("in_var", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleMask)}),
+             Param("in_var", ty.u32(), utils::Vector{Builtin(builtin::BuiltinValue::kSampleMask)}),
          },
          ty.u32(),
          utils::Vector{
@@ -1107,7 +1108,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kSampleMask),
+             Builtin(builtin::BuiltinValue::kSampleMask),
          });
 
     Inspector& inspector = Build();
@@ -1121,7 +1122,7 @@
 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskStructReferenced) {
     Structure("out_struct", utils::Vector{
                                 Member("inner_sample_mask", ty.u32(),
-                                       utils::Vector{Builtin(ast::BuiltinValue::kSampleMask)}),
+                                       utils::Vector{Builtin(builtin::BuiltinValue::kSampleMask)}),
                             });
 
     Func("ep_func", utils::Empty, ty("out_struct"),
@@ -1144,7 +1145,8 @@
 TEST_F(InspectorGetEntryPointTest, InputPositionSimpleReferenced) {
     Func("ep_func",
          utils::Vector{
-             Param("in_var", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+             Param("in_var", ty.vec4<f32>(),
+                   utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
          },
          ty.void_(),
          utils::Vector{
@@ -1165,7 +1167,7 @@
 TEST_F(InspectorGetEntryPointTest, InputPositionStructReferenced) {
     Structure("in_struct", utils::Vector{
                                Member("inner_position", ty.vec4<f32>(),
-                                      utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+                                      utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
                            });
 
     Func("ep_func",
@@ -1191,7 +1193,8 @@
 TEST_F(InspectorGetEntryPointTest, FrontFacingSimpleReferenced) {
     Func("ep_func",
          utils::Vector{
-             Param("in_var", ty.bool_(), utils::Vector{Builtin(ast::BuiltinValue::kFrontFacing)}),
+             Param("in_var", ty.bool_(),
+                   utils::Vector{Builtin(builtin::BuiltinValue::kFrontFacing)}),
          },
          ty.void_(),
          utils::Vector{
@@ -1212,7 +1215,7 @@
 TEST_F(InspectorGetEntryPointTest, FrontFacingStructReferenced) {
     Structure("in_struct", utils::Vector{
                                Member("inner_position", ty.bool_(),
-                                      utils::Vector{Builtin(ast::BuiltinValue::kFrontFacing)}),
+                                      utils::Vector{Builtin(builtin::BuiltinValue::kFrontFacing)}),
                            });
 
     Func("ep_func",
@@ -1238,7 +1241,7 @@
 TEST_F(InspectorGetEntryPointTest, SampleIndexSimpleReferenced) {
     Func("ep_func",
          utils::Vector{
-             Param("in_var", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+             Param("in_var", ty.u32(), utils::Vector{Builtin(builtin::BuiltinValue::kSampleIndex)}),
          },
          ty.void_(),
          utils::Vector{
@@ -1259,7 +1262,7 @@
 TEST_F(InspectorGetEntryPointTest, SampleIndexStructReferenced) {
     Structure("in_struct", utils::Vector{
                                Member("inner_position", ty.u32(),
-                                      utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+                                      utils::Vector{Builtin(builtin::BuiltinValue::kSampleIndex)}),
                            });
 
     Func("ep_func",
@@ -1286,7 +1289,7 @@
     Func("ep_func",
          utils::Vector{
              Param("in_var", ty.vec3<u32>(),
-                   utils::Vector{Builtin(ast::BuiltinValue::kNumWorkgroups)}),
+                   utils::Vector{Builtin(builtin::BuiltinValue::kNumWorkgroups)}),
          },
          ty.void_(),
          utils::Vector{
@@ -1303,10 +1306,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsStructReferenced) {
-    Structure("in_struct", utils::Vector{
-                               Member("inner_position", ty.vec3<u32>(),
-                                      utils::Vector{Builtin(ast::BuiltinValue::kNumWorkgroups)}),
-                           });
+    Structure("in_struct",
+              utils::Vector{
+                  Member("inner_position", ty.vec3<u32>(),
+                         utils::Vector{Builtin(builtin::BuiltinValue::kNumWorkgroups)}),
+              });
 
     Func("ep_func",
          utils::Vector{
@@ -1335,7 +1339,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kFragDepth),
+             Builtin(builtin::BuiltinValue::kFragDepth),
          });
 
     Inspector& inspector = Build();
@@ -1349,7 +1353,7 @@
 TEST_F(InspectorGetEntryPointTest, FragDepthStructReferenced) {
     Structure("out_struct", utils::Vector{
                                 Member("inner_frag_depth", ty.f32(),
-                                       utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
+                                       utils::Vector{Builtin(builtin::BuiltinValue::kFragDepth)}),
                             });
 
     Func("ep_func", utils::Empty, ty("out_struct"),
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index 44c2a61..6430c58 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -1509,7 +1509,7 @@
 }
 
 TEST_F(IR_BuilderImplTest, EmitLiteral_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto* expr = Expr(1.2_h);
     GlobalVar("a", ty.f16(), type::AddressSpace::kPrivate, expr);
 
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 265219d..0f8a6ed 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -42,7 +42,6 @@
 #include "src/tint/ast/disable_validation_attribute.h"
 #include "src/tint/ast/discard_statement.h"
 #include "src/tint/ast/enable.h"
-#include "src/tint/ast/extension.h"
 #include "src/tint/ast/float_literal_expression.h"
 #include "src/tint/ast/for_loop_statement.h"
 #include "src/tint/ast/id_attribute.h"
@@ -74,6 +73,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/extension.h"
 #include "src/tint/constant/composite.h"
 #include "src/tint/constant/splat.h"
 #include "src/tint/constant/value.h"
@@ -2036,7 +2036,7 @@
     /// Adds the extension to the list of enable directives at the top of the module.
     /// @param ext the extension to enable
     /// @return an `ast::Enable` enabling the given extension.
-    const ast::Enable* Enable(ast::Extension ext) {
+    const ast::Enable* Enable(builtin::Extension ext) {
         auto* enable = create<ast::Enable>(ext);
         AST().AddEnable(enable);
         return enable;
@@ -2046,7 +2046,7 @@
     /// @param source the enable source
     /// @param ext the extension to enable
     /// @return an `ast::Enable` enabling the given extension.
-    const ast::Enable* Enable(const Source& source, ast::Extension ext) {
+    const ast::Enable* Enable(const Source& source, builtin::Extension ext) {
         auto* enable = create<ast::Enable>(source, ext);
         AST().AddEnable(enable);
         return enable;
@@ -3436,14 +3436,14 @@
     /// @param source the source information
     /// @param builtin the builtin value
     /// @returns the builtin attribute pointer
-    const ast::BuiltinAttribute* Builtin(const Source& source, ast::BuiltinValue builtin) {
+    const ast::BuiltinAttribute* Builtin(const Source& source, builtin::BuiltinValue builtin) {
         return create<ast::BuiltinAttribute>(source, builtin);
     }
 
     /// Creates an ast::BuiltinAttribute
     /// @param builtin the builtin value
     /// @returns the builtin attribute pointer
-    const ast::BuiltinAttribute* Builtin(ast::BuiltinValue builtin) {
+    const ast::BuiltinAttribute* Builtin(builtin::BuiltinValue builtin) {
         return create<ast::BuiltinAttribute>(source_, builtin);
     }
 
diff --git a/src/tint/reader/spirv/enum_converter.cc b/src/tint/reader/spirv/enum_converter.cc
index 901401f..41792ce 100644
--- a/src/tint/reader/spirv/enum_converter.cc
+++ b/src/tint/reader/spirv/enum_converter.cc
@@ -64,40 +64,40 @@
     return type::AddressSpace::kUndefined;
 }
 
-ast::BuiltinValue EnumConverter::ToBuiltin(spv::BuiltIn b) {
+builtin::BuiltinValue EnumConverter::ToBuiltin(spv::BuiltIn b) {
     switch (b) {
         case spv::BuiltIn::Position:
-            return ast::BuiltinValue::kPosition;
+            return builtin::BuiltinValue::kPosition;
         case spv::BuiltIn::VertexIndex:
-            return ast::BuiltinValue::kVertexIndex;
+            return builtin::BuiltinValue::kVertexIndex;
         case spv::BuiltIn::InstanceIndex:
-            return ast::BuiltinValue::kInstanceIndex;
+            return builtin::BuiltinValue::kInstanceIndex;
         case spv::BuiltIn::FrontFacing:
-            return ast::BuiltinValue::kFrontFacing;
+            return builtin::BuiltinValue::kFrontFacing;
         case spv::BuiltIn::FragCoord:
-            return ast::BuiltinValue::kPosition;
+            return builtin::BuiltinValue::kPosition;
         case spv::BuiltIn::FragDepth:
-            return ast::BuiltinValue::kFragDepth;
+            return builtin::BuiltinValue::kFragDepth;
         case spv::BuiltIn::LocalInvocationId:
-            return ast::BuiltinValue::kLocalInvocationId;
+            return builtin::BuiltinValue::kLocalInvocationId;
         case spv::BuiltIn::LocalInvocationIndex:
-            return ast::BuiltinValue::kLocalInvocationIndex;
+            return builtin::BuiltinValue::kLocalInvocationIndex;
         case spv::BuiltIn::GlobalInvocationId:
-            return ast::BuiltinValue::kGlobalInvocationId;
+            return builtin::BuiltinValue::kGlobalInvocationId;
         case spv::BuiltIn::NumWorkgroups:
-            return ast::BuiltinValue::kNumWorkgroups;
+            return builtin::BuiltinValue::kNumWorkgroups;
         case spv::BuiltIn::WorkgroupId:
-            return ast::BuiltinValue::kWorkgroupId;
+            return builtin::BuiltinValue::kWorkgroupId;
         case spv::BuiltIn::SampleId:
-            return ast::BuiltinValue::kSampleIndex;
+            return builtin::BuiltinValue::kSampleIndex;
         case spv::BuiltIn::SampleMask:
-            return ast::BuiltinValue::kSampleMask;
+            return builtin::BuiltinValue::kSampleMask;
         default:
             break;
     }
 
     Fail() << "unknown SPIR-V builtin: " << uint32_t(b);
-    return ast::BuiltinValue::kUndefined;
+    return builtin::BuiltinValue::kUndefined;
 }
 
 type::TextureDimension EnumConverter::ToDim(spv::Dim dim, bool arrayed) {
diff --git a/src/tint/reader/spirv/enum_converter.h b/src/tint/reader/spirv/enum_converter.h
index f3cc037..7cdbfac 100644
--- a/src/tint/reader/spirv/enum_converter.h
+++ b/src/tint/reader/spirv/enum_converter.h
@@ -17,8 +17,8 @@
 
 #include "spirv/unified1/spirv.h"
 #include "spirv/unified1/spirv.hpp11"
-#include "src/tint/ast/builtin_value.h"
 #include "src/tint/ast/pipeline_stage.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"
@@ -51,7 +51,7 @@
     /// On failure, logs an error and returns kNone
     /// @param b the SPIR-V builtin
     /// @returns a Tint AST builtin
-    ast::BuiltinValue ToBuiltin(spv::BuiltIn b);
+    builtin::BuiltinValue ToBuiltin(spv::BuiltIn b);
 
     /// Converts a possibly arrayed SPIR-V Dim to a Tint texture dimension.
     /// On failure, logs an error and returns kNone
diff --git a/src/tint/reader/spirv/enum_converter_test.cc b/src/tint/reader/spirv/enum_converter_test.cc
index e0982ac..4d1a8fd 100644
--- a/src/tint/reader/spirv/enum_converter_test.cc
+++ b/src/tint/reader/spirv/enum_converter_test.cc
@@ -145,7 +145,7 @@
 struct BuiltinCase {
     spv::BuiltIn builtin;
     bool expect_success;
-    ast::BuiltinValue expected;
+    builtin::BuiltinValue expected;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinCase bc) {
     out << "BuiltinCase{ spv::BuiltIn::" << int(bc.builtin)
@@ -185,32 +185,35 @@
     EnumConverterGood_Input,
     SpvBuiltinTest,
     testing::Values(
-        BuiltinCase{spv::BuiltIn::Position, true, ast::BuiltinValue::kPosition},
-        BuiltinCase{spv::BuiltIn::InstanceIndex, true, ast::BuiltinValue::kInstanceIndex},
-        BuiltinCase{spv::BuiltIn::FrontFacing, true, ast::BuiltinValue::kFrontFacing},
-        BuiltinCase{spv::BuiltIn::FragCoord, true, ast::BuiltinValue::kPosition},
-        BuiltinCase{spv::BuiltIn::LocalInvocationId, true, ast::BuiltinValue::kLocalInvocationId},
+        BuiltinCase{spv::BuiltIn::Position, true, builtin::BuiltinValue::kPosition},
+        BuiltinCase{spv::BuiltIn::InstanceIndex, true, builtin::BuiltinValue::kInstanceIndex},
+        BuiltinCase{spv::BuiltIn::FrontFacing, true, builtin::BuiltinValue::kFrontFacing},
+        BuiltinCase{spv::BuiltIn::FragCoord, true, builtin::BuiltinValue::kPosition},
+        BuiltinCase{spv::BuiltIn::LocalInvocationId, true,
+                    builtin::BuiltinValue::kLocalInvocationId},
         BuiltinCase{spv::BuiltIn::LocalInvocationIndex, true,
-                    ast::BuiltinValue::kLocalInvocationIndex},
-        BuiltinCase{spv::BuiltIn::GlobalInvocationId, true, ast::BuiltinValue::kGlobalInvocationId},
-        BuiltinCase{spv::BuiltIn::NumWorkgroups, true, ast::BuiltinValue::kNumWorkgroups},
-        BuiltinCase{spv::BuiltIn::WorkgroupId, true, ast::BuiltinValue::kWorkgroupId},
-        BuiltinCase{spv::BuiltIn::SampleId, true, ast::BuiltinValue::kSampleIndex},
-        BuiltinCase{spv::BuiltIn::SampleMask, true, ast::BuiltinValue::kSampleMask}));
+                    builtin::BuiltinValue::kLocalInvocationIndex},
+        BuiltinCase{spv::BuiltIn::GlobalInvocationId, true,
+                    builtin::BuiltinValue::kGlobalInvocationId},
+        BuiltinCase{spv::BuiltIn::NumWorkgroups, true, builtin::BuiltinValue::kNumWorkgroups},
+        BuiltinCase{spv::BuiltIn::WorkgroupId, true, builtin::BuiltinValue::kWorkgroupId},
+        BuiltinCase{spv::BuiltIn::SampleId, true, builtin::BuiltinValue::kSampleIndex},
+        BuiltinCase{spv::BuiltIn::SampleMask, true, builtin::BuiltinValue::kSampleMask}));
 
 INSTANTIATE_TEST_SUITE_P(
     EnumConverterGood_Output,
     SpvBuiltinTest,
-    testing::Values(BuiltinCase{spv::BuiltIn::Position, true, ast::BuiltinValue::kPosition},
-                    BuiltinCase{spv::BuiltIn::FragDepth, true, ast::BuiltinValue::kFragDepth},
-                    BuiltinCase{spv::BuiltIn::SampleMask, true, ast::BuiltinValue::kSampleMask}));
+    testing::Values(BuiltinCase{spv::BuiltIn::Position, true, builtin::BuiltinValue::kPosition},
+                    BuiltinCase{spv::BuiltIn::FragDepth, true, builtin::BuiltinValue::kFragDepth},
+                    BuiltinCase{spv::BuiltIn::SampleMask, true,
+                                builtin::BuiltinValue::kSampleMask}));
 
 INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
                          SpvBuiltinTest,
                          testing::Values(BuiltinCase{static_cast<spv::BuiltIn>(9999), false,
-                                                     ast::BuiltinValue::kUndefined},
+                                                     builtin::BuiltinValue::kUndefined},
                                          BuiltinCase{static_cast<spv::BuiltIn>(9999), false,
-                                                     ast::BuiltinValue::kUndefined}));
+                                                     builtin::BuiltinValue::kUndefined}));
 
 // Dim
 
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index a23ca20..d63a8f1 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -21,7 +21,6 @@
 #include "src/tint/ast/bitcast_expression.h"
 #include "src/tint/ast/break_statement.h"
 #include "src/tint/ast/builtin_attribute.h"
-#include "src/tint/ast/builtin_value.h"
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/ast/continue_statement.h"
 #include "src/tint/ast/discard_statement.h"
@@ -32,6 +31,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/sem/builtin_type.h"
 #include "src/tint/transform/spirv_atomic.h"
 #include "src/tint/type/depth_texture.h"
@@ -760,7 +760,7 @@
 /// @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 == ast::BuiltinValue::kSampleMask;
+        return builtin->builtin == builtin::BuiltinValue::kSampleMask;
     }
     return false;
 }
@@ -1331,7 +1331,7 @@
                 // a gl_Position variable.  Substitute the type.
                 const Type* param_type = ty_.Vector(ty_.F32(), 4);
                 AttributeList out_decos{
-                    create<ast::BuiltinAttribute>(source, ast::BuiltinValue::kPosition)};
+                    create<ast::BuiltinAttribute>(source, builtin::BuiltinValue::kPosition)};
 
                 const auto var_name = namer_.GetName(var_id);
                 return_members.Push(
@@ -5038,6 +5038,11 @@
             // private variables.
             continue;
         }
+        if (def_info->skip == SkipReason::kOpaqueObject) {
+            // Intermediate values are never emitted for opaque objects. So they
+            // need neither hoisted let or var declarations.
+            continue;
+        }
         auto& local_def = def_info->local.value();
 
         if (local_def.num_uses == 0) {
diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc
index 2589d8e..8a373fd 100644
--- a/src/tint/reader/spirv/parser_impl.cc
+++ b/src/tint/reader/spirv/parser_impl.cc
@@ -1699,7 +1699,7 @@
                     break;
             }
             auto ast_builtin = enum_converter_.ToBuiltin(spv_builtin);
-            if (ast_builtin == ast::BuiltinValue::kUndefined) {
+            if (ast_builtin == builtin::BuiltinValue::kUndefined) {
                 // A diagnostic has already been emitted.
                 return false;
             }
diff --git a/src/tint/reader/spirv/parser_impl_handle_test.cc b/src/tint/reader/spirv/parser_impl_handle_test.cc
index 1270d31..fbf73e4 100644
--- a/src/tint/reader/spirv/parser_impl_handle_test.cc
+++ b/src/tint/reader/spirv/parser_impl_handle_test.cc
@@ -3828,6 +3828,83 @@
     ASSERT_EQ(expect, got);
 }
 
+TEST_F(SpvParserHandleTest, SamplerLoadedInEnclosingConstruct_DontGenerateVar) {
+    // crbug.com/tint/1839
+    // When a sampler is loaded in an enclosing structued construct, don't
+    // generate a variable for it. The ordinary tracing logic will find the
+    // originating variable anyway.
+    const auto assembly = Preamble() + R"(
+     OpEntryPoint Fragment %100 "main"
+     OpExecutionMode %100 OriginUpperLeft
+
+     OpName %var_im "var_im"
+     OpName %var_s "var_s"
+     OpDecorate %var_im DescriptorSet 0
+     OpDecorate %var_im Binding 0
+     OpDecorate %var_s DescriptorSet 0
+     OpDecorate %var_s Binding 1
+  %float = OpTypeFloat 32
+  %v4float = OpTypeVector %float 4
+  %v2float = OpTypeVector %float 2
+  %v2_0 = OpConstantNull %v2float
+     %im = OpTypeImage %float 2D 0 0 0 1 Unknown
+     %si = OpTypeSampledImage %im
+      %s = OpTypeSampler
+ %ptr_im = OpTypePointer UniformConstant %im
+  %ptr_s = OpTypePointer UniformConstant %s
+ %var_im = OpVariable %ptr_im UniformConstant
+  %var_s = OpVariable %ptr_s UniformConstant
+   %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %ptr_v4 = OpTypePointer Function %v4float
+   %bool = OpTypeBool
+   %true = OpConstantTrue %bool
+    %int = OpTypeInt 32 1
+  %int_0 = OpConstant %int 0
+
+    %100 = OpFunction %void None %voidfn
+  %entry = OpLabel
+      %1 = OpLoad %im %var_im
+      %2 = OpLoad %s %var_s
+           OpSelectionMerge %90 None
+           OpSwitch %int_0 %20
+
+     %20 = OpLabel
+           OpSelectionMerge %80 None
+           OpBranchConditional %true %30 %80
+
+     %30 = OpLabel
+    %si0 = OpSampledImage %si %1 %2
+     %t0 = OpImageSampleImplicitLod %v4float %si0 %v2_0
+           OpBranch %80
+
+     %80 = OpLabel
+           OpBranch %90
+
+     %90 = OpLabel
+           OpReturn
+           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();
+    EXPECT_TRUE(p->error().empty()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(switch(0i) {
+  default: {
+    if (true) {
+      let x_24 : vec4<f32> = textureSample(var_im, var_s, vec2<f32>());
+    }
+  }
+}
+return;
+)";
+    ASSERT_EQ(expect, got);
+}
+
 TEST_F(SpvParserHandleTest, ImageCoordinateCanBeHoistedConstant) {
     // Demonstrates fix for crbug.com/tint/1646
     // The problem is the coordinate for an image operation
diff --git a/src/tint/reader/wgsl/classify_template_args.cc b/src/tint/reader/wgsl/classify_template_args.cc
index 136ff18..0ccef95 100644
--- a/src/tint/reader/wgsl/classify_template_args.cc
+++ b/src/tint/reader/wgsl/classify_template_args.cc
@@ -72,33 +72,7 @@
         switch (tokens[i].type()) {
             // <identifier> + all type / builtin keywords that will become identifiers.
             case Token::Type::kIdentifier:
-            case Token::Type::kArray:
-            case Token::Type::kAtomic:
-            case Token::Type::kBitcast:
-            case Token::Type::kMat2x2:
-            case Token::Type::kMat2x3:
-            case Token::Type::kMat2x4:
-            case Token::Type::kMat3x2:
-            case Token::Type::kMat3x3:
-            case Token::Type::kMat3x4:
-            case Token::Type::kMat4x2:
-            case Token::Type::kMat4x3:
-            case Token::Type::kMat4x4:
-            case Token::Type::kPtr:
-            case Token::Type::kTextureMultisampled2d:
-            case Token::Type::kTextureSampled1d:
-            case Token::Type::kTextureSampled2d:
-            case Token::Type::kTextureSampled2dArray:
-            case Token::Type::kTextureSampled3d:
-            case Token::Type::kTextureSampledCube:
-            case Token::Type::kTextureSampledCubeArray:
-            case Token::Type::kTextureStorage1d:
-            case Token::Type::kTextureStorage2d:
-            case Token::Type::kTextureStorage2dArray:
-            case Token::Type::kVec2:
-            case Token::Type::kVec3:
-            case Token::Type::kVec4:
-            case Token::Type::kTextureStorage3d: {
+            case Token::Type::kBitcast: {
                 auto& next = tokens[i + 1];
                 if (next.type() == Token::Type::kLessThan) {
                     // ident '<'
diff --git a/src/tint/reader/wgsl/classify_template_args_test.cc b/src/tint/reader/wgsl/classify_template_args_test.cc
index fb9bcf9..9cf2c8f 100644
--- a/src/tint/reader/wgsl/classify_template_args_test.cc
+++ b/src/tint/reader/wgsl/classify_template_args_test.cc
@@ -232,9 +232,9 @@
                              {
                                  "vec3<i32>",
                                  {
-                                     T::kVec3,               // vec3
+                                     T::kIdentifier,         // vec3
                                      T::kTemplateArgsLeft,   // <
-                                     T::kI32,                // i32
+                                     T::kIdentifier,         // i32
                                      T::kTemplateArgsRight,  // >
                                      T::kEOF,
                                  },
@@ -242,9 +242,9 @@
                              {
                                  "vec3<i32>()",
                                  {
-                                     T::kVec3,               // vec3
+                                     T::kIdentifier,         // vec3
                                      T::kTemplateArgsLeft,   // <
-                                     T::kI32,                // i32
+                                     T::kIdentifier,         // i32
                                      T::kTemplateArgsRight,  // >
                                      T::kParenLeft,          // (
                                      T::kParenRight,         // )
@@ -254,11 +254,11 @@
                              {
                                  "array<vec3<i32>,5>",
                                  {
-                                     T::kArray,              // array
+                                     T::kIdentifier,         // array
                                      T::kTemplateArgsLeft,   // <
-                                     T::kVec3,               // vec3
+                                     T::kIdentifier,         // vec3
                                      T::kTemplateArgsLeft,   // <
-                                     T::kI32,                // i32
+                                     T::kIdentifier,         // i32
                                      T::kTemplateArgsRight,  // >
                                      T::kComma,              // ,
                                      T::kIntLiteral,         // 5
diff --git a/src/tint/reader/wgsl/lexer.cc b/src/tint/reader/wgsl/lexer.cc
index 722058c..46c15be 100644
--- a/src/tint/reader/wgsl/lexer.cc
+++ b/src/tint/reader/wgsl/lexer.cc
@@ -1118,18 +1118,9 @@
     if (str == "alias") {
         return {Token::Type::kAlias, source, "alias"};
     }
-    if (str == "array") {
-        return {Token::Type::kArray, source, "array"};
-    }
-    if (str == "atomic") {
-        return {Token::Type::kAtomic, source, "atomic"};
-    }
     if (str == "bitcast") {
         return {Token::Type::kBitcast, source, "bitcast"};
     }
-    if (str == "bool") {
-        return {Token::Type::kBool, source, "bool"};
-    }
     if (str == "break") {
         return {Token::Type::kBreak, source, "break"};
     }
@@ -1163,12 +1154,6 @@
     if (str == "enable") {
         return {Token::Type::kEnable, source, "enable"};
     }
-    if (str == "f16") {
-        return {Token::Type::kF16, source, "f16"};
-    }
-    if (str == "f32") {
-        return {Token::Type::kF32, source, "f32"};
-    }
     if (str == "fallthrough") {
         return {Token::Type::kFallthrough, source, "fallthrough"};
     }
@@ -1181,9 +1166,6 @@
     if (str == "for") {
         return {Token::Type::kFor, source, "for"};
     }
-    if (str == "i32") {
-        return {Token::Type::kI32, source, "i32"};
-    }
     if (str == "if") {
         return {Token::Type::kIf, source, "if"};
     }
@@ -1193,48 +1175,12 @@
     if (str == "loop") {
         return {Token::Type::kLoop, source, "loop"};
     }
-    if (str == "mat2x2") {
-        return {Token::Type::kMat2x2, source, "mat2x2"};
-    }
-    if (str == "mat2x3") {
-        return {Token::Type::kMat2x3, source, "mat2x3"};
-    }
-    if (str == "mat2x4") {
-        return {Token::Type::kMat2x4, source, "mat2x4"};
-    }
-    if (str == "mat3x2") {
-        return {Token::Type::kMat3x2, source, "mat3x2"};
-    }
-    if (str == "mat3x3") {
-        return {Token::Type::kMat3x3, source, "mat3x3"};
-    }
-    if (str == "mat3x4") {
-        return {Token::Type::kMat3x4, source, "mat3x4"};
-    }
-    if (str == "mat4x2") {
-        return {Token::Type::kMat4x2, source, "mat4x2"};
-    }
-    if (str == "mat4x3") {
-        return {Token::Type::kMat4x3, source, "mat4x3"};
-    }
-    if (str == "mat4x4") {
-        return {Token::Type::kMat4x4, source, "mat4x4"};
-    }
     if (str == "override") {
         return {Token::Type::kOverride, source, "override"};
     }
-    if (str == "ptr") {
-        return {Token::Type::kPtr, source, "ptr"};
-    }
     if (str == "return") {
         return {Token::Type::kReturn, source, "return"};
     }
-    if (str == "sampler") {
-        return {Token::Type::kSampler, source, "sampler"};
-    }
-    if (str == "sampler_comparison") {
-        return {Token::Type::kComparisonSampler, source, "sampler_comparison"};
-    }
     if (str == "static_assert") {
         return {Token::Type::kStaticAssert, source, "static_assert"};
     }
@@ -1244,78 +1190,15 @@
     if (str == "switch") {
         return {Token::Type::kSwitch, source, "switch"};
     }
-    if (str == "texture_1d") {
-        return {Token::Type::kTextureSampled1d, source, "texture_1d"};
-    }
-    if (str == "texture_2d") {
-        return {Token::Type::kTextureSampled2d, source, "texture_2d"};
-    }
-    if (str == "texture_2d_array") {
-        return {Token::Type::kTextureSampled2dArray, source, "texture_2d_array"};
-    }
-    if (str == "texture_3d") {
-        return {Token::Type::kTextureSampled3d, source, "texture_3d"};
-    }
-    if (str == "texture_cube") {
-        return {Token::Type::kTextureSampledCube, source, "texture_cube"};
-    }
-    if (str == "texture_cube_array") {
-        return {Token::Type::kTextureSampledCubeArray, source, "texture_cube_array"};
-    }
-    if (str == "texture_depth_2d") {
-        return {Token::Type::kTextureDepth2d, source, "texture_depth_2d"};
-    }
-    if (str == "texture_depth_2d_array") {
-        return {Token::Type::kTextureDepth2dArray, source, "texture_depth_2d_array"};
-    }
-    if (str == "texture_depth_cube") {
-        return {Token::Type::kTextureDepthCube, source, "texture_depth_cube"};
-    }
-    if (str == "texture_depth_cube_array") {
-        return {Token::Type::kTextureDepthCubeArray, source, "texture_depth_cube_array"};
-    }
-    if (str == "texture_depth_multisampled_2d") {
-        return {Token::Type::kTextureDepthMultisampled2d, source, "texture_depth_multisampled_2d"};
-    }
-    if (str == "texture_external") {
-        return {Token::Type::kTextureExternal, source, "texture_external"};
-    }
-    if (str == "texture_multisampled_2d") {
-        return {Token::Type::kTextureMultisampled2d, source, "texture_multisampled_2d"};
-    }
-    if (str == "texture_storage_1d") {
-        return {Token::Type::kTextureStorage1d, source, "texture_storage_1d"};
-    }
-    if (str == "texture_storage_2d") {
-        return {Token::Type::kTextureStorage2d, source, "texture_storage_2d"};
-    }
-    if (str == "texture_storage_2d_array") {
-        return {Token::Type::kTextureStorage2dArray, source, "texture_storage_2d_array"};
-    }
-    if (str == "texture_storage_3d") {
-        return {Token::Type::kTextureStorage3d, source, "texture_storage_3d"};
-    }
     if (str == "true") {
         return {Token::Type::kTrue, source, "true"};
     }
     if (str == "type") {
         return {Token::Type::kType, source, "type"};
     }
-    if (str == "u32") {
-        return {Token::Type::kU32, source, "u32"};
-    }
     if (str == "var") {
         return {Token::Type::kVar, source, "var"};
     }
-    if (str == "vec2") {
-        return {Token::Type::kVec2, source, "vec2"};
-    }
-    if (str == "vec3") {
-        return {Token::Type::kVec3, source, "vec3"};
-    }
-    if (str == "vec4") {
-        return {Token::Type::kVec4, source, "vec4"};
-    }
     if (str == "while") {
         return {Token::Type::kWhile, source, "while"};
     }
diff --git a/src/tint/reader/wgsl/lexer_test.cc b/src/tint/reader/wgsl/lexer_test.cc
index a376888..d2a875a 100644
--- a/src/tint/reader/wgsl/lexer_test.cc
+++ b/src/tint/reader/wgsl/lexer_test.cc
@@ -1054,75 +1054,37 @@
 
     EXPECT_EQ(list[1].source().range.begin.column, 1 + std::string(params.input).size());
 }
-INSTANTIATE_TEST_SUITE_P(
-    LexerTest,
-    KeywordTest,
-    testing::Values(TokenData{"alias", Token::Type::kAlias},
-                    TokenData{"array", Token::Type::kArray},
-                    TokenData{"bitcast", Token::Type::kBitcast},
-                    TokenData{"bool", Token::Type::kBool},
-                    TokenData{"break", Token::Type::kBreak},
-                    TokenData{"case", Token::Type::kCase},
-                    TokenData{"const", Token::Type::kConst},
-                    TokenData{"const_assert", Token::Type::kConstAssert},
-                    TokenData{"continue", Token::Type::kContinue},
-                    TokenData{"continuing", Token::Type::kContinuing},
-                    TokenData{"default", Token::Type::kDefault},
-                    TokenData{"diagnostic", Token::Type::kDiagnostic},
-                    TokenData{"discard", Token::Type::kDiscard},
-                    TokenData{"else", Token::Type::kElse},
-                    TokenData{"enable", Token::Type::kEnable},
-                    TokenData{"f32", Token::Type::kF32},
-                    TokenData{"fallthrough", Token::Type::kFallthrough},
-                    TokenData{"false", Token::Type::kFalse},
-                    TokenData{"fn", Token::Type::kFn},
-                    TokenData{"for", Token::Type::kFor},
-                    TokenData{"i32", Token::Type::kI32},
-                    TokenData{"if", Token::Type::kIf},
-                    TokenData{"let", Token::Type::kLet},
-                    TokenData{"loop", Token::Type::kLoop},
-                    TokenData{"mat2x2", Token::Type::kMat2x2},
-                    TokenData{"mat2x3", Token::Type::kMat2x3},
-                    TokenData{"mat2x4", Token::Type::kMat2x4},
-                    TokenData{"mat3x2", Token::Type::kMat3x2},
-                    TokenData{"mat3x3", Token::Type::kMat3x3},
-                    TokenData{"mat3x4", Token::Type::kMat3x4},
-                    TokenData{"mat4x2", Token::Type::kMat4x2},
-                    TokenData{"mat4x3", Token::Type::kMat4x3},
-                    TokenData{"mat4x4", Token::Type::kMat4x4},
-                    TokenData{"override", Token::Type::kOverride},
-                    TokenData{"ptr", Token::Type::kPtr},
-                    TokenData{"return", Token::Type::kReturn},
-                    TokenData{"sampler", Token::Type::kSampler},
-                    TokenData{"sampler_comparison", Token::Type::kComparisonSampler},
-                    TokenData{"static_assert", Token::Type::kStaticAssert},
-                    TokenData{"struct", Token::Type::kStruct},
-                    TokenData{"switch", Token::Type::kSwitch},
-                    TokenData{"texture_1d", Token::Type::kTextureSampled1d},
-                    TokenData{"texture_2d", Token::Type::kTextureSampled2d},
-                    TokenData{"texture_2d_array", Token::Type::kTextureSampled2dArray},
-                    TokenData{"texture_3d", Token::Type::kTextureSampled3d},
-                    TokenData{"texture_cube", Token::Type::kTextureSampledCube},
-                    TokenData{"texture_cube_array", Token::Type::kTextureSampledCubeArray},
-                    TokenData{"texture_depth_2d", Token::Type::kTextureDepth2d},
-                    TokenData{"texture_depth_2d_array", Token::Type::kTextureDepth2dArray},
-                    TokenData{"texture_depth_cube", Token::Type::kTextureDepthCube},
-                    TokenData{"texture_depth_cube_array", Token::Type::kTextureDepthCubeArray},
-                    TokenData{"texture_depth_multisampled_2d",
-                              Token::Type::kTextureDepthMultisampled2d},
-                    TokenData{"texture_multisampled_2d", Token::Type::kTextureMultisampled2d},
-                    TokenData{"texture_storage_1d", Token::Type::kTextureStorage1d},
-                    TokenData{"texture_storage_2d", Token::Type::kTextureStorage2d},
-                    TokenData{"texture_storage_2d_array", Token::Type::kTextureStorage2dArray},
-                    TokenData{"texture_storage_3d", Token::Type::kTextureStorage3d},
-                    TokenData{"true", Token::Type::kTrue},
-                    TokenData{"type", Token::Type::kType},
-                    TokenData{"u32", Token::Type::kU32},
-                    TokenData{"var", Token::Type::kVar},
-                    TokenData{"vec2", Token::Type::kVec2},
-                    TokenData{"vec3", Token::Type::kVec3},
-                    TokenData{"vec4", Token::Type::kVec4},
-                    TokenData{"while", Token::Type::kWhile}));
+INSTANTIATE_TEST_SUITE_P(LexerTest,
+                         KeywordTest,
+                         testing::Values(TokenData{"alias", Token::Type::kAlias},
+                                         TokenData{"bitcast", Token::Type::kBitcast},
+                                         TokenData{"break", Token::Type::kBreak},
+                                         TokenData{"case", Token::Type::kCase},
+                                         TokenData{"const", Token::Type::kConst},
+                                         TokenData{"const_assert", Token::Type::kConstAssert},
+                                         TokenData{"continue", Token::Type::kContinue},
+                                         TokenData{"continuing", Token::Type::kContinuing},
+                                         TokenData{"default", Token::Type::kDefault},
+                                         TokenData{"diagnostic", Token::Type::kDiagnostic},
+                                         TokenData{"discard", Token::Type::kDiscard},
+                                         TokenData{"else", Token::Type::kElse},
+                                         TokenData{"enable", Token::Type::kEnable},
+                                         TokenData{"fallthrough", Token::Type::kFallthrough},
+                                         TokenData{"false", Token::Type::kFalse},
+                                         TokenData{"fn", Token::Type::kFn},
+                                         TokenData{"for", Token::Type::kFor},
+                                         TokenData{"if", Token::Type::kIf},
+                                         TokenData{"let", Token::Type::kLet},
+                                         TokenData{"loop", Token::Type::kLoop},
+                                         TokenData{"override", Token::Type::kOverride},
+                                         TokenData{"return", Token::Type::kReturn},
+                                         TokenData{"static_assert", Token::Type::kStaticAssert},
+                                         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}));
 
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index 0fbb29f..c503353 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -422,24 +422,15 @@
             return add_error(t.source(), "enable directives don't take parenthesis");
         }
 
-        auto extension = ast::Extension::kUndefined;
-        if (t.Is(Token::Type::kF16)) {
-            // `f16` is a valid extension name and also a keyword
-            synchronized_ = true;
-            next();
-            extension = ast::Extension::kF16;
-        } else {
-            auto ext = expect_enum("extension", ast::ParseExtension, ast::kExtensionStrings);
-            if (ext.errored) {
-                return Failure::kErrored;
-            }
-            extension = ext.value;
+        auto ext = expect_enum("extension", builtin::ParseExtension, builtin::kExtensionStrings);
+        if (ext.errored) {
+            return Failure::kErrored;
         }
 
         if (!expect("enable directive", Token::Type::kSemicolon)) {
             return Failure::kErrored;
         }
-        builder_.AST().AddEnable(create<ast::Enable>(t.source(), extension));
+        builder_.AST().AddEnable(create<ast::Enable>(t.source(), ext.value));
         return kSuccess;
     });
 
@@ -723,229 +714,6 @@
     return VarDeclInfo{decl->source, decl->name, vq.address_space, vq.access, decl->type};
 }
 
-// texture_and_sampler_types
-//  : sampler_type
-//  | depth_texture_type
-//  | sampled_texture_type LESS_THAN type_specifier GREATER_THAN
-//  | multisampled_texture_type LESS_THAN type_specifier GREATER_THAN
-//  | storage_texture_type LESS_THAN texel_format
-//                         COMMA access_mode GREATER_THAN
-Maybe<ast::Type> ParserImpl::texture_and_sampler_types() {
-    auto type = sampler_type();
-    if (type.matched) {
-        return type;
-    }
-
-    type = depth_texture_type();
-    if (type.matched) {
-        return type;
-    }
-
-    type = external_texture();
-    if (type.matched) {
-        return type.value;
-    }
-
-    auto source_range = make_source_range();
-
-    auto dim = sampled_texture_type();
-    if (dim.matched) {
-        const char* use = "sampled texture type";
-
-        auto subtype = expect_template_arg_block(use, [&] { return expect_type(use); });
-        if (subtype.errored) {
-            return Failure::kErrored;
-        }
-
-        return builder_.ty.sampled_texture(source_range, dim.value, subtype.value);
-    }
-
-    auto ms_dim = multisampled_texture_type();
-    if (ms_dim.matched) {
-        const char* use = "multisampled texture type";
-
-        auto subtype = expect_template_arg_block(use, [&] { return expect_type(use); });
-        if (subtype.errored) {
-            return Failure::kErrored;
-        }
-
-        return builder_.ty.multisampled_texture(source_range, ms_dim.value, subtype.value);
-    }
-
-    auto storage = storage_texture_type();
-    if (storage.matched) {
-        const char* use = "storage texture type";
-        using StorageTextureInfo = std::pair<tint::type::TexelFormat, tint::type::Access>;
-        auto params = expect_template_arg_block(use, [&]() -> Expect<StorageTextureInfo> {
-            auto format = expect_texel_format(use);
-            if (format.errored) {
-                return Failure::kErrored;
-            }
-
-            if (!expect("access control", Token::Type::kComma)) {
-                return Failure::kErrored;
-            }
-
-            auto access = expect_access_mode(use);
-            if (access.errored) {
-                return Failure::kErrored;
-            }
-
-            return std::make_pair(format.value, access.value);
-        });
-
-        if (params.errored) {
-            return Failure::kErrored;
-        }
-
-        return builder_.ty.storage_texture(source_range, storage.value, params->first,
-                                           params->second);
-    }
-
-    return Failure::kNoMatch;
-}
-
-// sampler_type
-//  : SAMPLER
-//  | SAMPLER_COMPARISON
-Maybe<ast::Type> ParserImpl::sampler_type() {
-    Source source;
-    if (match(Token::Type::kSampler, &source)) {
-        return builder_.ty.sampler(source, type::SamplerKind::kSampler);
-    }
-
-    if (match(Token::Type::kComparisonSampler, &source)) {
-        return builder_.ty.sampler(source, type::SamplerKind::kComparisonSampler);
-    }
-
-    return Failure::kNoMatch;
-}
-
-// sampled_texture_type
-//  : TEXTURE_SAMPLED_1D
-//  | TEXTURE_SAMPLED_2D
-//  | TEXTURE_SAMPLED_2D_ARRAY
-//  | TEXTURE_SAMPLED_3D
-//  | TEXTURE_SAMPLED_CUBE
-//  | TEXTURE_SAMPLED_CUBE_ARRAY
-Maybe<const type::TextureDimension> ParserImpl::sampled_texture_type() {
-    if (match(Token::Type::kTextureSampled1d)) {
-        return type::TextureDimension::k1d;
-    }
-
-    if (match(Token::Type::kTextureSampled2d)) {
-        return type::TextureDimension::k2d;
-    }
-
-    if (match(Token::Type::kTextureSampled2dArray)) {
-        return type::TextureDimension::k2dArray;
-    }
-
-    if (match(Token::Type::kTextureSampled3d)) {
-        return type::TextureDimension::k3d;
-    }
-
-    if (match(Token::Type::kTextureSampledCube)) {
-        return type::TextureDimension::kCube;
-    }
-
-    if (match(Token::Type::kTextureSampledCubeArray)) {
-        return type::TextureDimension::kCubeArray;
-    }
-
-    return Failure::kNoMatch;
-}
-
-// external_texture
-//  : TEXTURE_EXTERNAL
-Maybe<ast::Type> ParserImpl::external_texture() {
-    Source source;
-    if (match(Token::Type::kTextureExternal, &source)) {
-        return builder_.ty.external_texture(source);
-    }
-
-    return Failure::kNoMatch;
-}
-
-// multisampled_texture_type
-//  : TEXTURE_MULTISAMPLED_2D
-Maybe<const type::TextureDimension> ParserImpl::multisampled_texture_type() {
-    if (match(Token::Type::kTextureMultisampled2d)) {
-        return type::TextureDimension::k2d;
-    }
-
-    return Failure::kNoMatch;
-}
-
-// storage_texture_type
-//  : TEXTURE_STORAGE_1D
-//  | TEXTURE_STORAGE_2D
-//  | TEXTURE_STORAGE_2D_ARRAY
-//  | TEXTURE_STORAGE_3D
-Maybe<const type::TextureDimension> ParserImpl::storage_texture_type() {
-    if (match(Token::Type::kTextureStorage1d)) {
-        return type::TextureDimension::k1d;
-    }
-    if (match(Token::Type::kTextureStorage2d)) {
-        return type::TextureDimension::k2d;
-    }
-    if (match(Token::Type::kTextureStorage2dArray)) {
-        return type::TextureDimension::k2dArray;
-    }
-    if (match(Token::Type::kTextureStorage3d)) {
-        return type::TextureDimension::k3d;
-    }
-
-    return Failure::kNoMatch;
-}
-
-// depth_texture_type
-//  : TEXTURE_DEPTH_2D
-//  | TEXTURE_DEPTH_2D_ARRAY
-//  | TEXTURE_DEPTH_CUBE
-//  | TEXTURE_DEPTH_CUBE_ARRAY
-//  | TEXTURE_DEPTH_MULTISAMPLED_2D
-Maybe<ast::Type> ParserImpl::depth_texture_type() {
-    Source source;
-    if (match(Token::Type::kTextureDepth2d, &source)) {
-        return builder_.ty.depth_texture(source, type::TextureDimension::k2d);
-    }
-    if (match(Token::Type::kTextureDepth2dArray, &source)) {
-        return builder_.ty.depth_texture(source, type::TextureDimension::k2dArray);
-    }
-    if (match(Token::Type::kTextureDepthCube, &source)) {
-        return builder_.ty.depth_texture(source, type::TextureDimension::kCube);
-    }
-    if (match(Token::Type::kTextureDepthCubeArray, &source)) {
-        return builder_.ty.depth_texture(source, type::TextureDimension::kCubeArray);
-    }
-    if (match(Token::Type::kTextureDepthMultisampled2d, &source)) {
-        return builder_.ty.depth_multisampled_texture(source, type::TextureDimension::k2d);
-    }
-    return Failure::kNoMatch;
-}
-
-// texel_format
-//  : 'rgba8unorm'
-//  | 'rgba8snorm'
-//  | 'rgba8uint'
-//  | 'rgba8sint'
-//  | 'rgba16uint'
-//  | 'rgba16sint'
-//  | 'rgba16float'
-//  | 'r32uint'
-//  | 'r32sint'
-//  | 'r32float'
-//  | 'rg32uint'
-//  | 'rg32sint'
-//  | 'rg32float'
-//  | 'rgba32uint'
-//  | 'rgba32sint'
-//  | 'rgba32float'
-Expect<type::TexelFormat> ParserImpl::expect_texel_format(std::string_view use) {
-    return expect_enum("texel format", type::ParseTexelFormat, type::kTexelFormatStrings, use);
-}
-
 Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_ident_with_optional_type_specifier(
     std::string_view use,
     bool allow_inferred) {
@@ -1063,146 +831,27 @@
     return builder_.ty.alias(make_source_range_from(source), name.value, type.value);
 }
 
-// vec_prefix
-//   : 'vec2'
-//   | 'vec3'
-//   | 'vec4'
-Maybe<uint32_t> ParserImpl::vec_prefix() {
-    auto& t = peek();
-    if (!t.IsVector()) {
+// type_specifier
+//   : IDENTIFIER template_arguments?
+Maybe<ast::Type> ParserImpl::type_specifier() {
+    MultiTokenSource source(this);
+    auto& ident = peek();
+    if (!match(Token::Type::kIdentifier)) {
         return Failure::kNoMatch;
     }
-    next();
 
-    if (t.Is(Token::Type::kVec3)) {
-        return 3u;
-    }
-    if (t.Is(Token::Type::kVec4)) {
-        return 4u;
-    }
-    return 2u;
-}
-
-// mat_prefix
-//   : 'mat2x2'
-//   | 'mat2x3'
-//   | 'mat2x4'
-//   | 'mat3x2'
-//   | 'mat3x3'
-//   | 'mat3x4'
-//   | 'mat4x2'
-//   | 'mat4x3'
-//   | 'mat4x4'
-Maybe<ParserImpl::MatrixDimensions> ParserImpl::mat_prefix() {
-    auto& t = peek();
-    if (!t.IsMatrix()) {
-        return Failure::kNoMatch;
-    }
-    next();
-
-    uint32_t columns = 2;
-    if (t.IsMat3xN()) {
-        columns = 3;
-    } else if (t.IsMat4xN()) {
-        columns = 4;
-    }
-    if (t.IsMatNx3()) {
-        return MatrixDimensions{columns, 3};
-    }
-    if (t.IsMatNx4()) {
-        return MatrixDimensions{columns, 4};
-    }
-    return MatrixDimensions{columns, 2};
-}
-
-// type_specifier_without_ident:
-//   : BOOL
-//   | F16
-//   | F32
-//   | I32
-//   | U32
-//   | ARRAY LESS_THAN type_specifier ( COMMA element_count_expression )? GREATER_THAN
-//   | ATOMIC LESS_THAN type_specifier GREATER_THAN
-//   | PTR LESS_THAN address_space COMMA type_specifier ( COMMA access_mode )? GREATER_THAN
-//   | mat_prefix LESS_THAN type_specifier GREATER_THAN
-//   | vec_prefix LESS_THAN type_specifier GREATER_THAN
-//   | texture_and_sampler_types
-Maybe<ast::Type> ParserImpl::type_specifier_without_ident() {
-    auto& t = peek();
-
-    if (match(Token::Type::kBool)) {
-        return builder_.ty.bool_(t.source());
+    if (!peek_is(Token::Type::kTemplateArgsLeft)) {
+        return builder_.ty(builder_.Ident(source.Source(), ident.to_str()));
     }
 
-    if (match(Token::Type::kF16)) {
-        return builder_.ty.f16(t.source());
-    }
-
-    if (match(Token::Type::kF32)) {
-        return builder_.ty.f32(t.source());
-    }
-
-    if (match(Token::Type::kI32)) {
-        return builder_.ty.i32(t.source());
-    }
-
-    if (match(Token::Type::kU32)) {
-        return builder_.ty.u32(t.source());
-    }
-
-    if (t.Is(Token::Type::kArray) &&
-        (peek_is(Token::Type::kTemplateArgsLeft, 1) || peek_is(Token::Type::kLessThan, 1))) {
-        if (match(Token::Type::kArray)) {
-            return expect_type_specifier_array(t.source());
-        }
-    }
-
-    if (match(Token::Type::kAtomic)) {
-        return expect_type_specifier_atomic(t.source());
-    }
-
-    if (match(Token::Type::kPtr)) {
-        return expect_type_specifier_pointer(t.source());
-    }
-
-    if (t.IsMatrix() &&
-        (peek_is(Token::Type::kTemplateArgsLeft, 1) || peek_is(Token::Type::kLessThan, 1))) {
-        auto mat = mat_prefix();
-        if (mat.matched) {
-            return expect_type_specifier_matrix(t.source(), mat.value);
-        }
-    }
-
-    if (t.IsVector() &&
-        (peek_is(Token::Type::kTemplateArgsLeft, 1) || peek_is(Token::Type::kLessThan, 1))) {
-        auto vec = vec_prefix();
-        if (vec.matched) {
-            return expect_type_specifier_vector(t.source(), vec.value);
-        }
-    }
-
-    auto texture_or_sampler = texture_and_sampler_types();
-    if (texture_or_sampler.errored) {
+    auto args = expect_template_arg_block("type template arguments", [&]() {
+        return expect_expression_list("type template argument list",
+                                      Token::Type::kTemplateArgsRight);
+    });
+    if (args.errored) {
         return Failure::kErrored;
     }
-    if (texture_or_sampler.matched) {
-        return texture_or_sampler;
-    }
-
-    return Failure::kNoMatch;
-}
-
-// type_specifier
-//   : IDENTIFIER
-//   | type_specifier_without_ident
-Maybe<ast::Type> ParserImpl::type_specifier() {
-    auto& t = peek();
-    Source source;
-    if (match(Token::Type::kIdentifier, &source)) {
-        return builder_.ty(source, t.to_str());
-    }
-
-    return type_specifier_without_ident();
+    return builder_.ty(builder_.Ident(source.Source(), ident.to_str(), std::move(args.value)));
 }
 
 template <typename ENUM, size_t N>
@@ -1251,123 +900,6 @@
     return type.value;
 }
 
-// LESS_THAN address_space COMMA type_specifier ( COMMA access_mode )? GREATER_THAN
-Expect<ast::Type> ParserImpl::expect_type_specifier_pointer(const Source& s) {
-    const char* use = "ptr declaration";
-
-    auto address_space = type::AddressSpace::kNone;
-    auto access = type::Access::kUndefined;
-
-    auto subtype = expect_template_arg_block(use, [&]() -> Expect<ast::Type> {
-        auto sc = expect_address_space(use);
-        if (sc.errored) {
-            return Failure::kErrored;
-        }
-        address_space = sc.value;
-
-        if (!expect(use, Token::Type::kComma)) {
-            return Failure::kErrored;
-        }
-
-        auto type = expect_type(use);
-        if (type.errored) {
-            return Failure::kErrored;
-        }
-
-        if (match(Token::Type::kComma)) {
-            auto ac = expect_access_mode(use);
-            if (ac.errored) {
-                return Failure::kErrored;
-            }
-            access = ac.value;
-        }
-
-        return type.value;
-    });
-
-    if (subtype.errored) {
-        return Failure::kErrored;
-    }
-
-    return builder_.ty.pointer(make_source_range_from(s), subtype.value, address_space, access);
-}
-
-// LESS_THAN type_specifier GREATER_THAN
-Expect<ast::Type> ParserImpl::expect_type_specifier_atomic(const Source& s) {
-    const char* use = "atomic declaration";
-
-    auto subtype = expect_template_arg_block(use, [&] { return expect_type(use); });
-    if (subtype.errored) {
-        return Failure::kErrored;
-    }
-
-    return builder_.ty.atomic(make_source_range_from(s), subtype.value);
-}
-
-// LESS_THAN type_specifier GREATER_THAN
-Expect<ast::Type> ParserImpl::expect_type_specifier_vector(const Source& s, uint32_t count) {
-    const char* use = "vector";
-    auto ty = expect_template_arg_block(use, [&] { return expect_type(use); });
-    if (ty.errored) {
-        return Failure::kErrored;
-    }
-
-    return builder_.ty.vec(make_source_range_from(s), ty.value, count);
-}
-
-// LESS_THAN type_specifier ( COMMA element_count_expression )? GREATER_THAN
-Expect<ast::Type> ParserImpl::expect_type_specifier_array(const Source& s) {
-    const char* use = "array declaration";
-
-    struct TypeAndSize {
-        ast::Type type;
-        const ast::Expression* size = nullptr;
-    };
-
-    auto type_size = expect_template_arg_block(use, [&]() -> Expect<TypeAndSize> {
-        auto type = expect_type(use);
-        if (type.errored) {
-            return Failure::kErrored;
-        }
-
-        if (!match(Token::Type::kComma)) {
-            return TypeAndSize{type.value, nullptr};
-        }
-
-        auto size = element_count_expression();
-        if (size.errored) {
-            return Failure::kErrored;
-        }
-        if (!size.matched) {
-            return add_error(peek(), "expected array size expression");
-        }
-
-        return TypeAndSize{type.value, size.value};
-    });
-
-    if (type_size.errored) {
-        return Failure::kErrored;
-    }
-
-    if (type_size->size) {
-        return builder_.ty.array(make_source_range_from(s), type_size->type, type_size->size);
-    } else {
-        return builder_.ty.array(make_source_range_from(s), type_size->type);
-    }
-}
-
-// LESS_THAN type_specifier GREATER_THAN
-Expect<ast::Type> ParserImpl::expect_type_specifier_matrix(const Source& s,
-                                                           const MatrixDimensions& dims) {
-    const char* use = "matrix";
-    auto ty = expect_template_arg_block(use, [&] { return expect_type(use); });
-    if (ty.errored) {
-        return Failure::kErrored;
-    }
-
-    return builder_.ty.mat(make_source_range_from(s), ty.value, dims.columns, dims.rows);
-}
-
 // address_space
 //   : 'function'
 //   | 'private'
@@ -1648,8 +1180,8 @@
 //   | sample_mask
 //   | vertex_index
 //   | workgroup_id
-Expect<ast::BuiltinValue> ParserImpl::expect_builtin() {
-    return expect_enum("builtin", ast::ParseBuiltinValue, ast::kBuiltinValueStrings);
+Expect<builtin::BuiltinValue> ParserImpl::expect_builtin() {
+    return expect_enum("builtin", builtin::ParseBuiltinValue, builtin::kBuiltinValueStrings);
 }
 
 // compound_statement
@@ -2519,59 +2051,14 @@
     return continuing_compound_statement();
 }
 
-// callable
-//   : type_specifier_without_ident
-//   | ARRAY
-//   | mat_prefix
-//   | vec_prefix
-//
-//  Note, `ident` is pulled out to `primary_expression` as it's the only one that
-//  doesn't create a `type`. Then we can just return a `type` from here on match and
-//  deal with `ident` in `primary_expression.
-Maybe<const ast::IdentifierExpression*> ParserImpl::callable() {
-    auto& t = peek();
-
-    //  This _must_ match `type_specifier_without_ident` before any of the other types as they're
-    //  all prefixes of the types and we want to match the longer `vec3<f32>` then the shorter
-    //  prefix match of `vec3`.
-    auto ty = type_specifier_without_ident();
-    if (ty.errored) {
-        return Failure::kErrored;
-    }
-    if (ty.matched) {
-        return ty->expr;
-    }
-
-    if (match(Token::Type::kArray)) {
-        return builder_.ty.array<Infer>(make_source_range_from(t.source()));
-    }
-
-    auto vec = vec_prefix();
-    if (vec.matched) {
-        return builder_.ty.vec<Infer>(make_source_range_from(t.source()), vec.value);
-    }
-
-    auto mat = mat_prefix();
-    if (mat.matched) {
-        return builder_.ty.mat<Infer>(make_source_range_from(t.source()), mat.value.columns,
-                                      mat.value.rows);
-    }
-
-    return Failure::kNoMatch;
-}
-
 // primary_expression
 //   : BITCAST LESS_THAN type_specifier GREATER_THAN paren_expression
-//   | callable argument_expression_list
 //   | const_literal
 //   | IDENT argument_expression_list?
 //   | paren_expression
 //
 // Note, PAREN_LEFT ( expression ( COMMA expression ) * COMMA? )? PAREN_RIGHT is replaced
 // with `argument_expression_list`.
-//
-// Note, this is matching the `callable` ident here instead of having to come from
-// callable so we can return a `type` from callable.
 Maybe<const ast::Expression*> ParserImpl::primary_expression() {
     auto& t = peek();
 
@@ -2591,19 +2078,6 @@
         return builder_.Bitcast(t.source(), type.value, params.value);
     }
 
-    auto call = callable();
-    if (call.errored) {
-        return Failure::kErrored;
-    }
-    if (call.matched) {
-        auto params = expect_argument_expression_list("type initializer");
-        if (params.errored) {
-            return Failure::kErrored;
-        }
-
-        return builder_.Call(t.source(), call.value, std::move(params.value));
-    }
-
     auto lit = const_literal();
     if (lit.errored) {
         return Failure::kErrored;
@@ -2613,14 +2087,19 @@
     }
 
     if (t.IsIdentifier()) {
+        MultiTokenSource source(this);
         next();
 
-        if (Source source; match(Token::Type::kTemplateArgsLeft, &source)) {
-            return add_error(
-                source,
-                "'<' treated as the start of a template argument list, which is not supported for "
-                "user-declared types or functions. If you intended less-than, wrap the expression "
-                "in parentheses");
+        const ast::Identifier* ident = nullptr;
+
+        if (peek_is(Token::Type::kTemplateArgsLeft)) {
+            auto tmpl_args = expect_template_arg_block("template arguments", [&]() {
+                return expect_expression_list("template argument list",
+                                              Token::Type::kTemplateArgsRight);
+            });
+            ident = builder_.Ident(source.Source(), t.to_str(), std::move(tmpl_args.value));
+        } else {
+            ident = builder_.Ident(source.Source(), t.to_str());
         }
 
         if (peek_is(Token::Type::kParenLeft)) {
@@ -2629,10 +2108,10 @@
                 return Failure::kErrored;
             }
 
-            return builder_.Call(t.source(), t.to_str(), std::move(params.value));
+            return builder_.Call(source.Source(), ident, std::move(params.value));
         }
 
-        return builder_.Expr(t.source(), t.to_str());
+        return builder_.Expr(ident);
     }
 
     if (t.Is(Token::Type::kParenLeft)) {
@@ -3041,6 +2520,41 @@
     return create<ast::BinaryExpression>(tok_op.source(), op, lhs, rhs.value);
 }
 
+Expect<const ast::Expression*> ParserImpl::expect_expression() {
+    auto& t = peek();
+    auto expr = expression();
+    if (expr.errored) {
+        return Failure::kErrored;
+    }
+    if (expr.matched) {
+        return expr.value;
+    }
+    return add_error(t, "expected expression");
+}
+
+Expect<utils::Vector<const ast::Expression*, 3>> ParserImpl::expect_expression_list(
+    std::string_view use,
+    Token::Type terminator) {
+    utils::Vector<const ast::Expression*, 3> exprs;
+    while (continue_parsing()) {
+        auto expr = expect_expression();
+        if (expr.errored) {
+            return Failure::kErrored;
+        }
+        exprs.Push(expr.value);
+        if (peek_is(terminator)) {
+            break;
+        }
+        if (!expect(use, Token::Type::kComma)) {
+            return Failure::kErrored;
+        }
+        if (peek_is(terminator)) {
+            break;
+        }
+    }
+    return exprs;
+}
+
 // expression
 //   : unary_expression bitwise_expression.post.unary_expression
 //   | unary_expression relational_expression.post.unary_expression
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index 455300d..fe42cac 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -25,9 +25,6 @@
 #include "src/tint/program_builder.h"
 #include "src/tint/reader/wgsl/parser_impl_detail.h"
 #include "src/tint/reader/wgsl/token.h"
-#include "src/tint/type/access.h"
-#include "src/tint/type/storage_texture.h"
-#include "src/tint/type/texture_dimension.h"
 
 namespace tint::ast {
 class BreakStatement;
@@ -447,18 +444,6 @@
     /// Parses a `type_alias_decl` grammar element
     /// @returns the type alias or nullptr on error
     Maybe<const ast::Alias*> type_alias_decl();
-    /// Parses a `callable` grammar element
-    /// @returns the type or nullptr
-    Maybe<const ast::IdentifierExpression*> callable();
-    /// Parses a `vec_prefix` grammar element
-    /// @returns the vector size or nullptr
-    Maybe<uint32_t> vec_prefix();
-    /// Parses a `mat_prefix` grammar element
-    /// @returns the matrix dimensions or nullptr
-    Maybe<MatrixDimensions> mat_prefix();
-    /// Parses a `type_specifier_without_ident` grammar element
-    /// @returns the parsed Type or nullptr if none matched.
-    Maybe<ast::Type> type_specifier_without_ident();
     /// Parses a `type_specifier` grammar element
     /// @returns the parsed Type or nullptr if none matched.
     Maybe<ast::Type> type_specifier();
@@ -481,33 +466,6 @@
     ///        by the declaration, then this vector is cleared before returning.
     /// @returns the parsed function, nullptr otherwise
     Maybe<const ast::Function*> function_decl(AttributeList& attrs);
-    /// Parses a `texture_and_sampler_types` grammar element
-    /// @returns the parsed Type or nullptr if none matched.
-    Maybe<ast::Type> texture_and_sampler_types();
-    /// Parses a `sampler_type` grammar element
-    /// @returns the parsed Type or nullptr if none matched.
-    Maybe<ast::Type> sampler_type();
-    /// Parses a `multisampled_texture_type` grammar element
-    /// @returns returns the multisample texture dimension or kNone if none
-    /// matched.
-    Maybe<const type::TextureDimension> multisampled_texture_type();
-    /// Parses a `sampled_texture_type` grammar element
-    /// @returns returns the sample texture dimension or kNone if none matched.
-    Maybe<const type::TextureDimension> sampled_texture_type();
-    /// Parses a `storage_texture_type` grammar element
-    /// @returns returns the storage texture dimension.
-    /// Returns kNone if none matched.
-    Maybe<const type::TextureDimension> storage_texture_type();
-    /// Parses a `depth_texture_type` grammar element
-    /// @returns the parsed Type or nullptr if none matched.
-    Maybe<ast::Type> depth_texture_type();
-    /// Parses a 'texture_external_type' grammar element
-    /// @returns the parsed Type or nullptr if none matched
-    Maybe<ast::Type> external_texture();
-    /// Parses a `texel_format` grammar element
-    /// @param use a description of what was being parsed if an error was raised
-    /// @returns returns the texel format or kNone if none matched.
-    Expect<type::TexelFormat> expect_texel_format(std::string_view use);
     /// Parses a `const_assert_statement` grammar element
     /// @returns returns the const assert, if it matched.
     Maybe<const ast::ConstAssert*> const_assert_statement();
@@ -540,7 +498,7 @@
     /// Parses a builtin identifier, erroring if the next token does not match a
     /// valid builtin name.
     /// @returns the parsed builtin.
-    Expect<ast::BuiltinValue> expect_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
@@ -638,6 +596,15 @@
     /// Parses the `expression` grammar rule
     /// @returns the parsed expression or nullptr
     Maybe<const ast::Expression*> expression();
+    /// Parses the `expression` grammar rule
+    /// @returns the parsed expression or error
+    Expect<const ast::Expression*> expect_expression();
+    /// Parses a comma separated expression list
+    /// @param use the use of the expression list
+    /// @param terminator the terminating token for the list
+    /// @returns the parsed expression list or error
+    Expect<utils::Vector<const ast::Expression*, 3>> expect_expression_list(std::string_view use,
+                                                                            Token::Type terminator);
     /// Parses the `bitwise_expression.post.unary_expression` grammar element
     /// @param lhs the left side of the expression
     /// @returns the parsed expression or nullptr
@@ -891,12 +858,6 @@
     /// Used to ensure that all attributes are consumed.
     bool expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> list);
 
-    Expect<ast::Type> expect_type_specifier_pointer(const Source& s);
-    Expect<ast::Type> expect_type_specifier_atomic(const Source& s);
-    Expect<ast::Type> expect_type_specifier_vector(const Source& s, uint32_t count);
-    Expect<ast::Type> expect_type_specifier_array(const Source& s);
-    Expect<ast::Type> expect_type_specifier_matrix(const Source& s, const MatrixDimensions& dims);
-
     /// Parses the given enum, providing sensible error messages if the next token does not match
     /// any of the enum values.
     /// @param name the name of the enumerator
diff --git a/src/tint/reader/wgsl/parser_impl_callable_test.cc b/src/tint/reader/wgsl/parser_impl_callable_test.cc
deleted file mode 100644
index 647e2b2..0000000
--- a/src/tint/reader/wgsl/parser_impl_callable_test.cc
+++ /dev/null
@@ -1,117 +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/ast/test_helper.h"
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-using namespace tint::number_suffixes;  // NOLINT
-
-TEST_F(ParserImplTest, Callable_Array) {
-    auto p = parser("array");
-    auto t = p->callable();
-    ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "array");
-}
-
-TEST_F(ParserImplTest, Callable_VecPrefix) {
-    auto p = parser("vec3");
-    auto t = p->callable();
-    ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "vec3");
-}
-
-TEST_F(ParserImplTest, Callable_MatPrefix) {
-    auto p = parser("mat3x2");
-    auto t = p->callable();
-    ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "mat3x2");
-}
-
-TEST_F(ParserImplTest, Callable_TypeDecl_Array) {
-    auto p = parser("array<f32, 2>");
-    auto t = p->callable();
-    ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("array", "f32", 2_a));
-}
-
-TEST_F(ParserImplTest, Callable_TypeDecl_Array_Runtime) {
-    auto p = parser("array<f32>");
-    auto t = p->callable();
-    ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("array", "f32"));
-}
-
-TEST_F(ParserImplTest, Callable_TypeDecl_VecPrefix) {
-    auto p = parser("vec3<f32>");
-    auto t = p->callable();
-    ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("vec3", "f32"));
-}
-
-TEST_F(ParserImplTest, Callable_TypeDecl_MatPrefix) {
-    auto p = parser("mat3x2<f32>");
-    auto t = p->callable();
-    ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("mat3x2", "f32"));
-}
-
-TEST_F(ParserImplTest, Callable_NoMatch) {
-    auto p = parser("ident");
-    auto t = p->callable();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_EQ(nullptr, t.value);
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc b/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc
deleted file mode 100644
index f807943..0000000
--- a/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc
+++ /dev/null
@@ -1,87 +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/ast/test_helper.h"
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-#include "src/tint/type/depth_texture.h"
-#include "src/tint/type/texture_dimension.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, DepthTextureType_Invalid) {
-    auto p = parser("1234");
-    auto t = p->depth_texture_type();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, DepthTextureType_2d) {
-    auto p = parser("texture_depth_2d");
-    auto t = p->depth_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "texture_depth_2d");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
-}
-
-TEST_F(ParserImplTest, DepthTextureType_2dArray) {
-    auto p = parser("texture_depth_2d_array");
-    auto t = p->depth_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "texture_depth_2d_array");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 23u}}));
-}
-
-TEST_F(ParserImplTest, DepthTextureType_Cube) {
-    auto p = parser("texture_depth_cube");
-    auto t = p->depth_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "texture_depth_cube");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
-}
-
-TEST_F(ParserImplTest, DepthTextureType_CubeArray) {
-    auto p = parser("texture_depth_cube_array");
-    auto t = p->depth_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "texture_depth_cube_array");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
-}
-
-TEST_F(ParserImplTest, DepthTextureType_Multisampled2d) {
-    auto p = parser("texture_depth_multisampled_2d");
-    auto t = p->depth_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "texture_depth_multisampled_2d");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 30u}}));
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
index 260175d..fea7c2d 100644
--- a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
@@ -30,7 +30,7 @@
     auto& ast = program.AST();
     ASSERT_EQ(ast.Enables().Length(), 1u);
     auto* enable = ast.Enables()[0];
-    EXPECT_EQ(enable->extension, ast::Extension::kF16);
+    EXPECT_EQ(enable->extension, builtin::Extension::kF16);
     ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
     EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
 }
@@ -48,8 +48,8 @@
     ASSERT_EQ(ast.Enables().Length(), 2u);
     auto* enable_a = ast.Enables()[0];
     auto* enable_b = ast.Enables()[1];
-    EXPECT_EQ(enable_a->extension, ast::Extension::kF16);
-    EXPECT_EQ(enable_b->extension, ast::Extension::kF16);
+    EXPECT_EQ(enable_a->extension, builtin::Extension::kF16);
+    EXPECT_EQ(enable_b->extension, builtin::Extension::kF16);
     ASSERT_EQ(ast.GlobalDeclarations().Length(), 2u);
     EXPECT_EQ(ast.GlobalDeclarations()[0], enable_a);
     EXPECT_EQ(ast.GlobalDeclarations()[1], enable_b);
@@ -146,6 +146,7 @@
         p->translation_unit();
         EXPECT_TRUE(p->has_error());
         EXPECT_EQ(p->error(), R"(1:8: expected extension
+Did you mean 'f16'?
 Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
         auto program = p->program();
         auto& ast = program.AST();
@@ -168,7 +169,7 @@
     // Accept the enable directive although it caused an error
     ASSERT_EQ(ast.Enables().Length(), 1u);
     auto* enable = ast.Enables()[0];
-    EXPECT_EQ(enable->extension, ast::Extension::kF16);
+    EXPECT_EQ(enable->extension, builtin::Extension::kF16);
     ASSERT_EQ(ast.GlobalDeclarations().Length(), 2u);
     EXPECT_EQ(ast.GlobalDeclarations()[1], enable);
 }
@@ -188,7 +189,7 @@
     // Accept the enable directive although it cause an error
     ASSERT_EQ(ast.Enables().Length(), 1u);
     auto* enable = ast.Enables()[0];
-    EXPECT_EQ(enable->extension, ast::Extension::kF16);
+    EXPECT_EQ(enable->extension, builtin::Extension::kF16);
     ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
     EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
 }
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 9e5d1a7..d40898a 100644
--- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -193,7 +193,7 @@
 
 TEST_F(ParserImplErrorTest, InitializerExprMissingLParen) {
     EXPECT("fn f() { x = vec2<u32>1,2); }",
-           R"(test.wgsl:1:23 error: expected '(' for type initializer
+           R"(test.wgsl:1:23 error: expected ';' for assignment statement
 fn f() { x = vec2<u32>1,2); }
                       ^
 )");
@@ -201,7 +201,7 @@
 
 TEST_F(ParserImplErrorTest, InitializerExprMissingRParen) {
     EXPECT("fn f() { x = vec2<u32>(1,2; }",
-           R"(test.wgsl:1:27 error: expected ')' for type initializer
+           R"(test.wgsl:1:27 error: expected ')' for function call
 fn f() { x = vec2<u32>(1,2; }
                           ^
 )");
@@ -575,17 +575,9 @@
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclConstMissingLParen) {
-    EXPECT("const i : vec2<i32> = vec2<i32>;",
-           R"(test.wgsl:1:32 error: expected '(' for type initializer
-const i : vec2<i32> = vec2<i32>;
-                               ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
     EXPECT("const i : vec2<i32> = vec2<i32>(1., 2.;",
-           R"(test.wgsl:1:39 error: expected ')' for type initializer
+           R"(test.wgsl:1:39 error: expected ')' for function call
 const i : vec2<i32> = vec2<i32>(1., 2.;
                                       ^
 )");
@@ -628,7 +620,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingLParen) {
     EXPECT("const i : vec2<i32> = vec2<i32> 1, 2);",
-           R"(test.wgsl:1:33 error: expected '(' for type initializer
+           R"(test.wgsl:1:33 error: expected ';' for 'const' declaration
 const i : vec2<i32> = vec2<i32> 1, 2);
                                 ^
 )");
@@ -636,7 +628,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingRParen) {
     EXPECT("const i : vec2<i32> = vec2<i32>(1, 2;",
-           R"(test.wgsl:1:37 error: expected ')' for type initializer
+           R"(test.wgsl:1:37 error: expected ')' for function call
 const i : vec2<i32> = vec2<i32>(1, 2;
                                     ^
 )");
@@ -658,54 +650,22 @@
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureMissingLessThan) {
-    EXPECT("var x : texture_1d;",
-           R"(test.wgsl:1:19 error: expected '<' for sampled texture type
-var x : texture_1d;
-                  ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureMissingGreaterThan) {
     EXPECT("var x : texture_1d<f32;",
-           R"(test.wgsl:1:19 error: missing closing '>' for sampled texture type
+           R"(test.wgsl:1:19 error: expected ';' for variable declaration
 var x : texture_1d<f32;
                   ^
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureInvalidSubtype) {
-    EXPECT("var x : texture_1d<1>;",
-           R"(test.wgsl:1:20 error: invalid type for sampled texture type
-var x : texture_1d<1>;
-                   ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureMissingLessThan) {
-    EXPECT("var x : texture_multisampled_2d;",
-           R"(test.wgsl:1:32 error: expected '<' for multisampled texture type
-var x : texture_multisampled_2d;
-                               ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureMissingGreaterThan) {
     EXPECT("var x : texture_multisampled_2d<f32;",
-           R"(test.wgsl:1:32 error: missing closing '>' for multisampled texture type
+           R"(test.wgsl:1:32 error: expected ';' for variable declaration
 var x : texture_multisampled_2d<f32;
                                ^
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureInvalidSubtype) {
-    EXPECT("var x : texture_multisampled_2d<1>;",
-           R"(test.wgsl:1:33 error: invalid type for multisampled texture type
-var x : texture_multisampled_2d<1>;
-                                ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclConstAssertMissingCondThenEOF) {
     EXPECT("const_assert", R"(test.wgsl:1:13 error: unable to parse condition expression
 const_assert
@@ -829,17 +789,9 @@
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingLessThan) {
-    EXPECT("var x : texture_storage_2d;",
-           R"(test.wgsl:1:27 error: expected '<' for storage texture type
-var x : texture_storage_2d;
-                          ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingGreaterThan) {
     EXPECT("var x : texture_storage_2d<r32uint, read;",
-           R"(test.wgsl:1:27 error: missing closing '>' for storage texture type
+           R"(test.wgsl:1:27 error: expected ';' for variable declaration
 var x : texture_storage_2d<r32uint, read;
                           ^
 )");
@@ -847,22 +799,12 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingSubtype) {
     EXPECT("var x : texture_storage_2d<>;",
-           R"(test.wgsl:1:28 error: expected texel format for storage texture type
-Possible values: 'bgra8unorm', 'r32float', 'r32sint', 'r32uint', 'rg32float', 'rg32sint', 'rg32uint', 'rgba16float', 'rgba16sint', 'rgba16uint', 'rgba32float', 'rgba32sint', 'rgba32uint', 'rgba8sint', 'rgba8snorm', 'rgba8uint', 'rgba8unorm'
+           R"(test.wgsl:1:28 error: expected expression
 var x : texture_storage_2d<>;
                            ^
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingInvalidSubtype) {
-    EXPECT("var x : texture_storage_2d<1>;",
-           R"(test.wgsl:1:28 error: expected texel format for storage texture type
-Possible values: 'bgra8unorm', 'r32float', 'r32sint', 'r32uint', 'rg32float', 'rg32sint', 'rg32uint', 'rgba16float', 'rgba16sint', 'rgba16uint', 'rgba32float', 'rgba32sint', 'rgba32uint', 'rgba8sint', 'rgba8snorm', 'rgba8uint', 'rgba8unorm'
-var x : texture_storage_2d<1>;
-                           ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingIdentifier) {
     EXPECT("struct {};",
            R"(test.wgsl:1:8 error: expected identifier for struct declaration
@@ -993,28 +935,12 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingGreaterThan) {
     EXPECT("var i : array<u32, 3;",
-           R"(test.wgsl:1:14 error: missing closing '>' for array declaration
+           R"(test.wgsl:1:14 error: expected ';' for variable declaration
 var i : array<u32, 3;
              ^
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingType) {
-    EXPECT("var i : array<1, 3>;",
-           R"(test.wgsl:1:15 error: invalid type for array declaration
-var i : array<1, 3>;
-              ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingSize) {
-    EXPECT("var i : array<u32, >;",
-           R"(test.wgsl:1:20 error: expected array size expression
-var i : array<u32, >;
-                   ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayInvalidSize) {
     EXPECT("var i : array<u32, !>;",
            R"(test.wgsl:1:21 error: unable to parse right side of ! expression
@@ -1175,19 +1101,12 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingGreaterThan) {
-    EXPECT("var i : mat4x4<u32;", R"(test.wgsl:1:15 error: missing closing '>' for matrix
+    EXPECT("var i : mat4x4<u32;", R"(test.wgsl:1:15 error: expected ';' for variable declaration
 var i : mat4x4<u32;
               ^
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingType) {
-    EXPECT("var i : mat4x4<1>;", R"(test.wgsl:1:16 error: invalid type for matrix
-var i : mat4x4<1>;
-               ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclVarMissingSemicolon) {
     EXPECT("var i : i32",
            R"(test.wgsl:1:12 error: expected ';' for variable declaration
@@ -1196,63 +1115,14 @@
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingLessThan) {
-    EXPECT("var i : ptr;",
-           R"(test.wgsl:1:12 error: expected '<' for ptr declaration
-var i : ptr;
-           ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingGreaterThan) {
     EXPECT("var i : ptr<private, u32;",
-           R"(test.wgsl:1:12 error: missing closing '>' for ptr declaration
+           R"(test.wgsl:1:12 error: expected ';' for variable declaration
 var i : ptr<private, u32;
            ^
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingComma) {
-    EXPECT("var i : ptr<private u32>;",
-           R"(test.wgsl:1:21 error: expected ',' for ptr declaration
-var i : ptr<private u32>;
-                    ^^^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingAddressSpace) {
-    EXPECT("var i : ptr<meow, u32>;",
-           R"(test.wgsl:1:13 error: expected address space for ptr declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup'
-var i : ptr<meow, u32>;
-            ^^^^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingType) {
-    EXPECT("var i : ptr<private, 1>;",
-           R"(test.wgsl:1:22 error: invalid type for ptr declaration
-var i : ptr<private, 1>;
-                     ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclVarAtomicMissingLessThan) {
-    EXPECT("var i : atomic;",
-           R"(test.wgsl:1:15 error: expected '<' for atomic declaration
-var i : atomic;
-              ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclVarAtomicMissingGreaterThan) {
-    EXPECT("var i : atomic<u32 x;",
-           R"(test.wgsl:1:15 error: missing closing '>' for atomic declaration
-var i : atomic<u32 x;
-              ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclInvalidClass) {
     EXPECT("var<fish> i : i32",
            R"(test.wgsl:1:5 error: expected address space for variable declaration
@@ -1271,19 +1141,12 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingGreaterThan) {
-    EXPECT("var i : vec3<u32;", R"(test.wgsl:1:13 error: missing closing '>' for vector
+    EXPECT("var i : vec3<u32;", R"(test.wgsl:1:13 error: expected ';' for variable declaration
 var i : vec3<u32;
             ^
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingType) {
-    EXPECT("var i : vec3<1>;", R"(test.wgsl:1:14 error: invalid type for vector
-var i : vec3<1>;
-             ^
-)");
-}
-
 TEST_F(ParserImplErrorTest, IfStmtMissingRParen) {
     EXPECT("fn f() { if (true {} }", R"(test.wgsl:1:19 error: expected ')'
 fn f() { if (true {} }
diff --git a/src/tint/reader/wgsl/parser_impl_expression_test.cc b/src/tint/reader/wgsl/parser_impl_expression_test.cc
index 68b3be3..0de3dea 100644
--- a/src/tint/reader/wgsl/parser_impl_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_expression_test.cc
@@ -474,9 +474,10 @@
     std::vector<Case> out;
     for (auto& lhs_op : kBinaryOperators) {
         for (auto& rhs_op : kBinaryOperators) {
-            bool should_parse = (lhs_op.can_follow_without_paren & rhs_op.bit) &&
-                                !ParsedAsTemplateArgumentList(lhs_op, rhs_op);
-            out.push_back({lhs_op, rhs_op, should_parse});
+            if (!ParsedAsTemplateArgumentList(lhs_op, rhs_op)) {
+                bool should_parse = lhs_op.can_follow_without_paren & rhs_op.bit;
+                out.push_back({lhs_op, rhs_op, should_parse});
+            }
         }
     }
     return out;
@@ -498,14 +499,8 @@
         EXPECT_EQ(e.value, nullptr);
         EXPECT_TRUE(p->has_error());
         std::stringstream expected;
-        if (ParsedAsTemplateArgumentList(GetParam().lhs_op, GetParam().rhs_op)) {
-            expected << "1:3: '<' treated as the start of a template argument list, which is not "
-                        "supported for user-declared types or functions. If you intended "
-                        "less-than, wrap the expression in parentheses";
-        } else {
-            expected << "1:3: mixing '" << GetParam().lhs_op.symbol << "' and '"
-                     << GetParam().rhs_op.symbol << "' requires parenthesis";
-        }
+        expected << "1:3: mixing '" << GetParam().lhs_op.symbol << "' and '"
+                 << GetParam().rhs_op.symbol << "' requires parenthesis";
         EXPECT_EQ(p->error(), expected.str());
     }
 }
diff --git a/src/tint/reader/wgsl/parser_impl_external_texture_test.cc b/src/tint/reader/wgsl/parser_impl_external_texture_test.cc
deleted file mode 100644
index 4bd5cb1..0000000
--- a/src/tint/reader/wgsl/parser_impl_external_texture_test.cc
+++ /dev/null
@@ -1,37 +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/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, ExternalTextureType_Invalid) {
-    auto p = parser("1234");
-    auto t = p->external_texture();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, ExternalTextureType) {
-    auto p = parser("texture_external");
-    auto t = p->external_texture();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
-}
-
-}  // 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 4829294..696d791 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,7 @@
     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, ast::BuiltinValue::kPosition);
+    EXPECT_EQ(attrs_0[0]->As<ast::BuiltinAttribute>()->builtin, builtin::BuiltinValue::kPosition);
 
     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_primary_expression_test.cc b/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
index b7b0d85..5dab39f 100644
--- a/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
@@ -77,26 +77,6 @@
     ASSERT_EQ(call->args.Length(), 0u);
 }
 
-TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) {
-    auto p = parser("vec4<if>(2., 3., 4., 5.)");
-    auto e = p->primary_expression();
-    EXPECT_FALSE(e.matched);
-    EXPECT_TRUE(e.errored);
-    EXPECT_EQ(e.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:6: invalid type for vector");
-}
-
-TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingLeftParen) {
-    auto p = parser("vec4<f32> 2., 3., 4., 5.)");
-    auto e = p->primary_expression();
-    EXPECT_FALSE(e.matched);
-    EXPECT_TRUE(e.errored);
-    EXPECT_EQ(e.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:11: expected '(' for type initializer");
-}
-
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingRightParen) {
     auto p = parser("vec4<f32>(2., 3., 4., 5.");
     auto e = p->primary_expression();
@@ -104,7 +84,7 @@
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:25: expected ')' for type initializer");
+    EXPECT_EQ(p->error(), "1:25: expected ')' for function call");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidValue) {
@@ -114,7 +94,7 @@
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:5: expected ')' for type initializer");
+    EXPECT_EQ(p->error(), "1:5: expected ')' for function call");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructInitializer_Empty) {
@@ -318,18 +298,5 @@
     EXPECT_EQ(p->error(), "1:14: unable to parse expression");
 }
 
-TEST_F(ParserImplTest, PrimaryExpression_Template) {
-    auto p = parser("a<b>()");
-    auto e = p->primary_expression();
-    EXPECT_FALSE(e.matched);
-    EXPECT_TRUE(e.errored);
-    EXPECT_EQ(e.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(),
-              "1:2: '<' treated as the start of a template argument list, which is not supported "
-              "for user-declared types or functions. If you intended less-than, wrap the "
-              "expression in parentheses");
-}
-
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc b/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc
deleted file mode 100644
index 5a2d38a..0000000
--- a/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-#include "src/tint/type/texture_dimension.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, SampledTextureType_Invalid) {
-    auto p = parser("1234");
-    auto t = p->sampled_texture_type();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_1d) {
-    auto p = parser("texture_1d");
-    auto t = p->sampled_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::k1d);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_2d) {
-    auto p = parser("texture_2d");
-    auto t = p->sampled_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::k2d);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_2dArray) {
-    auto p = parser("texture_2d_array");
-    auto t = p->sampled_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::k2dArray);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_3d) {
-    auto p = parser("texture_3d");
-    auto t = p->sampled_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::k3d);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_Cube) {
-    auto p = parser("texture_cube");
-    auto t = p->sampled_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::kCube);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_kCubeArray) {
-    auto p = parser("texture_cube_array");
-    auto t = p->sampled_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::kCubeArray);
-    EXPECT_FALSE(p->has_error());
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_sampler_test.cc b/src/tint/reader/wgsl/parser_impl_sampler_test.cc
deleted file mode 100644
index b88ac2d..0000000
--- a/src/tint/reader/wgsl/parser_impl_sampler_test.cc
+++ /dev/null
@@ -1,53 +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/ast/test_helper.h"
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, SamplerType_Invalid) {
-    auto p = parser("1234");
-    auto t = p->sampler_type();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, nullptr);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SamplerType_Sampler) {
-    auto p = parser("sampler");
-    auto t = p->sampler_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "sampler");
-    EXPECT_FALSE(p->has_error());
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
-}
-
-TEST_F(ParserImplTest, SamplerType_ComparisonSampler) {
-    auto p = parser("sampler_comparison");
-    auto t = p->sampler_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "sampler_comparison");
-    EXPECT_FALSE(p->has_error());
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc b/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc
deleted file mode 100644
index e1c25b6..0000000
--- a/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc
+++ /dev/null
@@ -1,66 +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"
-#include "src/tint/type/texture_dimension.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, StorageTextureType_Invalid) {
-    auto p = parser("abc");
-    auto t = p->storage_texture_type();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, StorageTextureType_1d) {
-    auto p = parser("texture_storage_1d");
-    auto t = p->storage_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::k1d);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, StorageTextureType_2d) {
-    auto p = parser("texture_storage_2d");
-    auto t = p->storage_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::k2d);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, StorageTextureType_2dArray) {
-    auto p = parser("texture_storage_2d_array");
-    auto t = p->storage_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::k2dArray);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, StorageTextureType_3d) {
-    auto p = parser("texture_storage_3d");
-    auto t = p->storage_texture_type();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TextureDimension::k3d);
-    EXPECT_FALSE(p->has_error());
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_test.cc b/src/tint/reader/wgsl/parser_impl_test.cc
index 6df73c4..2927cab 100644
--- a/src/tint/reader/wgsl/parser_impl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_test.cc
@@ -153,7 +153,8 @@
     auto p = parser(">= vec2<u32>");
     auto& n = p->next();
     ASSERT_TRUE(n.Is(Token::Type::kGreaterThanEqual));
-    EXPECT_TRUE(p->peek_is(Token::Type::kVec2)) << "expected: vec2 got: " << p->peek().to_name();
+    EXPECT_TRUE(p->peek_is(Token::Type::kIdentifier))
+        << "expected: vec2 got: " << p->peek().to_name();
     EXPECT_TRUE(p->peek_is(Token::Type::kTemplateArgsLeft, 1))
         << "expected: < got: " << p->peek(1).to_name();
 }
@@ -164,7 +165,7 @@
     ASSERT_TRUE(n.Is(Token::Type::kGreaterThanEqual));
     EXPECT_TRUE(p->peek_is(Token::Type::kGreaterThanEqual))
         << "expected: >= got: " << p->peek().to_name();
-    EXPECT_TRUE(p->peek_is(Token::Type::kVec2, 1))
+    EXPECT_TRUE(p->peek_is(Token::Type::kIdentifier, 1))
         << "expected: vec2 got: " << p->peek(1).to_name();
     EXPECT_TRUE(p->peek_is(Token::Type::kTemplateArgsLeft, 2))
         << "expected: < got: " << p->peek(2).to_name();
@@ -190,7 +191,8 @@
     auto p = parser(">= vec2<u32>");
     auto& n = p->next();
     ASSERT_TRUE(n.Is(Token::Type::kGreaterThanEqual));
-    EXPECT_TRUE(p->peek_is(Token::Type::kVec2)) << "expected: vec2 got: " << p->peek().to_name();
+    EXPECT_TRUE(p->peek_is(Token::Type::kIdentifier))
+        << "expected: vec2 got: " << p->peek().to_name();
 
     p->split_token(Token::Type::kGreaterThan, Token::Type::kEqual);
     ASSERT_TRUE(n.Is(Token::Type::kGreaterThan));
diff --git a/src/tint/reader/wgsl/parser_impl_texel_format_test.cc b/src/tint/reader/wgsl/parser_impl_texel_format_test.cc
deleted file mode 100644
index 046feef..0000000
--- a/src/tint/reader/wgsl/parser_impl_texel_format_test.cc
+++ /dev/null
@@ -1,158 +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 {
-
-TEST_F(ParserImplTest, TexelFormat_Invalid) {
-    auto p = parser("1234");
-    auto t = p->expect_texel_format("test");
-    EXPECT_TRUE(t.errored);
-    EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), R"(1:1: expected texel format for test
-Possible values: 'bgra8unorm', 'r32float', 'r32sint', 'r32uint', 'rg32float', 'rg32sint', 'rg32uint', 'rgba16float', 'rgba16sint', 'rgba16uint', 'rgba32float', 'rgba32sint', 'rgba32uint', 'rgba8sint', 'rgba8snorm', 'rgba8uint', 'rgba8unorm')");
-}
-
-TEST_F(ParserImplTest, TexelFormat_R32Uint) {
-    auto p = parser("r32uint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kR32Uint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_R32Sint) {
-    auto p = parser("r32sint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kR32Sint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_R32Float) {
-    auto p = parser("r32float");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kR32Float);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba8Unorm) {
-    auto p = parser("rgba8unorm");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba8Unorm);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba8Snorm) {
-    auto p = parser("rgba8snorm");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba8Snorm);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba8Uint) {
-    auto p = parser("rgba8uint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba8Uint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba8Sint) {
-    auto p = parser("rgba8sint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba8Sint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rg32Uint) {
-    auto p = parser("rg32uint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRg32Uint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rg32Sint) {
-    auto p = parser("rg32sint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRg32Sint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rg32Float) {
-    auto p = parser("rg32float");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRg32Float);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba16Uint) {
-    auto p = parser("rgba16uint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba16Uint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba16Sint) {
-    auto p = parser("rgba16sint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba16Sint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba16Float) {
-    auto p = parser("rgba16float");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba16Float);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba32Uint) {
-    auto p = parser("rgba32uint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba32Uint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba32Sint) {
-    auto p = parser("rgba32sint");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba32Sint);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TexelFormat_Rgba32Float) {
-    auto p = parser("rgba32float");
-    auto t = p->expect_texel_format("test");
-    EXPECT_FALSE(t.errored);
-    EXPECT_EQ(t.value, type::TexelFormat::kRgba32Float);
-    EXPECT_FALSE(p->has_error());
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc b/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc
deleted file mode 100644
index 3163377..0000000
--- a/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc
+++ /dev/null
@@ -1,185 +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/ast/test_helper.h"
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-#include "src/tint/type/depth_texture.h"
-#include "src/tint/type/multisampled_texture.h"
-#include "src/tint/type/sampled_texture.h"
-#include "src/tint/type/texture_dimension.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) {
-    auto p = parser("1234");
-    auto t = p->texture_and_sampler_types();
-    EXPECT_EQ(t.value, nullptr);
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) {
-    auto p = parser("sampler");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "sampler");
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
-    auto p = parser("sampler_comparison");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "sampler_comparison");
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
-    auto p = parser("texture_depth_2d");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "texture_depth_2d");
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
-    auto p = parser("texture_1d<f32>");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("texture_1d", "f32"));
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
-    auto p = parser("texture_2d<i32>");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("texture_2d", "i32"));
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
-    auto p = parser("texture_3d<u32>");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("texture_3d", "u32"));
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) {
-    auto p = parser("texture_multisampled_2d<i32>");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value,
-                         ast::Template("texture_multisampled_2d", "i32"));
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 29u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) {
-    auto p = parser("texture_multisampled_2d<>");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(t.value, nullptr);
-    EXPECT_FALSE(t.matched);
-    EXPECT_TRUE(t.errored);
-    EXPECT_EQ(p->error(), "1:25: invalid type for multisampled texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingLessThan) {
-    auto p = parser("texture_multisampled_2d");
-    auto t = p->texture_and_sampler_types();
-    EXPECT_EQ(t.value, nullptr);
-    EXPECT_FALSE(t.matched);
-    EXPECT_TRUE(t.errored);
-    EXPECT_EQ(p->error(), "1:24: expected '<' for multisampled texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) {
-    auto p = parser("texture_multisampled_2d<u32");
-    auto t = p->texture_and_sampler_types();
-    EXPECT_EQ(t.value, nullptr);
-    EXPECT_FALSE(t.matched);
-    EXPECT_TRUE(t.errored);
-    EXPECT_EQ(p->error(), "1:24: missing closing '>' for multisampled texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dRg32Float) {
-    auto p = parser("texture_storage_1d<rg32float, read>");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value,
-                         ast::Template("texture_storage_1d", "rg32float", "read"));
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 36u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR32Uint) {
-    auto p = parser("texture_storage_2d<r32uint, write>");
-    auto t = p->texture_and_sampler_types();
-    ASSERT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value,
-                         ast::Template("texture_storage_2d", "r32uint", "write"));
-    EXPECT_EQ(t->expr->source.range, (Source::Range{{1u, 1u}, {1u, 35u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) {
-    auto p = parser("texture_storage_1d<>");
-    auto t = p->texture_and_sampler_types();
-    EXPECT_EQ(t.value, nullptr);
-    EXPECT_FALSE(t.matched);
-    EXPECT_TRUE(t.errored);
-    EXPECT_EQ(p->error(), R"(1:20: expected texel format for storage texture type
-Possible values: 'bgra8unorm', 'r32float', 'r32sint', 'r32uint', 'rg32float', 'rg32sint', 'rg32uint', 'rgba16float', 'rgba16sint', 'rgba16uint', 'rgba32float', 'rgba32sint', 'rgba32uint', 'rgba8sint', 'rgba8snorm', 'rgba8uint', 'rgba8unorm')");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) {
-    auto p = parser("texture_storage_1d<r32uint, read");
-    auto t = p->texture_and_sampler_types();
-    EXPECT_EQ(t.value, nullptr);
-    EXPECT_FALSE(t.matched);
-    EXPECT_TRUE(t.errored);
-    EXPECT_EQ(p->error(), "1:19: missing closing '>' for storage texture type");
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
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 d1adde2..b40d887 100644
--- a/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
@@ -127,24 +127,6 @@
                                          VecData{"vec3<f32>", 3, {{1u, 1u}, {1u, 10u}}},
                                          VecData{"vec4<f32>", 4, {{1u, 1u}, {1u, 10u}}}));
 
-class VecMissingGreaterThanTest : public ParserImplTestWithParam<VecData> {};
-
-TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:5: missing closing '>' for vector");
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         VecMissingGreaterThanTest,
-                         testing::Values(VecData{"vec2<f32", 2, {}},
-                                         VecData{"vec3<f32", 3, {}},
-                                         VecData{"vec4<f32", 4, {}}));
-
 class VecMissingType : public ParserImplTestWithParam<VecData> {};
 
 TEST_P(VecMissingType, Handles_Missing_Type) {
@@ -155,7 +137,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:6: invalid type for vector");
+    ASSERT_EQ(p->error(), "1:6: expected expression");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          VecMissingType,
@@ -202,36 +184,6 @@
     EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25}}));
 }
 
-TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) {
-    auto p = parser("ptr private, f32>");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:5: expected '<' for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThanAfterType) {
-    auto p = parser("ptr<function, f32");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:4: missing closing '>' for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThanAfterAccess) {
-    auto p = parser("ptr<function, f32, read");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:4: missing closing '>' for ptr declaration");
-}
-
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingCommaAfterAddressSpace) {
     auto p = parser("ptr<function f32>");
     auto t = p->type_specifier();
@@ -239,7 +191,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:14: expected ',' for ptr declaration");
+    ASSERT_EQ(p->error(), "1:14: expected ',' for type template argument list");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingCommaAfterAccess) {
@@ -249,7 +201,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
+    ASSERT_EQ(p->error(), "1:19: expected ',' for type template argument list");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingAddressSpace) {
@@ -259,29 +211,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:5: expected address space for ptr declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
-
-TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
-    auto p = parser("ptr<function,>");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:14: invalid type for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDecl_Ptr_MissingAccess) {
-    auto p = parser("ptr<function, i32, >");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:20: expected access control for ptr declaration
-Possible values: 'read', 'read_write', 'write')");
+    ASSERT_EQ(p->error(), R"(1:5: expected expression)");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
@@ -291,32 +221,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:5: expected address space for ptr declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
-
-TEST_F(ParserImplTest, TypeDecl_Ptr_BadAddressSpace) {
-    auto p = parser("ptr<unknown, f32>");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(),
-              R"(1:5: expected address space for ptr declaration
-Did you mean 'uniform'?
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
-
-TEST_F(ParserImplTest, TypeDecl_Ptr_BadAccess) {
-    auto p = parser("ptr<function, i32, unknown>");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:20: expected access control for ptr declaration
-Possible values: 'read', 'read_write', 'write')");
+    ASSERT_EQ(p->error(), R"(1:5: expected expression)");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Atomic) {
@@ -344,26 +249,6 @@
     EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
 }
 
-TEST_F(ParserImplTest, TypeDecl_Atomic_MissingLessThan) {
-    auto p = parser("atomic f32>");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:8: expected '<' for atomic declaration");
-}
-
-TEST_F(ParserImplTest, TypeDecl_Atomic_MissingGreaterThan) {
-    auto p = parser("atomic<f32");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:7: missing closing '>' for atomic declaration");
-}
-
 TEST_F(ParserImplTest, TypeDecl_Atomic_MissingType) {
     auto p = parser("atomic<>");
     auto t = p->type_specifier();
@@ -371,7 +256,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:8: invalid type for atomic declaration");
+    ASSERT_EQ(p->error(), "1:8: expected expression");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_AbstractIntLiteralSize) {
@@ -486,26 +371,6 @@
     ASSERT_EQ(p->error(), "1:13: unable to parse right side of ! expression");
 }
 
-TEST_F(ParserImplTest, TypeDecl_Array_MissingSize) {
-    auto p = parser("array<f32,>");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:11: expected array size expression");
-}
-
-TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) {
-    auto p = parser("array<f32");
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:6: missing closing '>' for array declaration");
-}
-
 TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) {
     auto p = parser("array<f32 3>");
     auto t = p->type_specifier();
@@ -513,7 +378,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration");
+    ASSERT_EQ(p->error(), "1:11: expected ',' for type template argument list");
 }
 
 struct MatrixData {
@@ -556,30 +421,6 @@
                                          MatrixData{"mat4x3<f32>", 4, 3, {{1u, 1u}, {1u, 12u}}},
                                          MatrixData{"mat4x4<f32>", 4, 4, {{1u, 1u}, {1u, 12u}}}));
 
-class MatrixMissingGreaterThanTest : public ParserImplTestWithParam<MatrixData> {};
-
-TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-    auto t = p->type_specifier();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:7: missing closing '>' for matrix");
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         MatrixMissingGreaterThanTest,
-                         testing::Values(MatrixData{"mat2x2<f32", 2, 2, {}},
-                                         MatrixData{"mat2x3<f32", 2, 3, {}},
-                                         MatrixData{"mat2x4<f32", 2, 4, {}},
-                                         MatrixData{"mat3x2<f32", 3, 2, {}},
-                                         MatrixData{"mat3x3<f32", 3, 3, {}},
-                                         MatrixData{"mat3x4<f32", 3, 4, {}},
-                                         MatrixData{"mat4x2<f32", 4, 2, {}},
-                                         MatrixData{"mat4x3<f32", 4, 3, {}},
-                                         MatrixData{"mat4x4<f32", 4, 4, {}}));
-
 class MatrixMissingType : public ParserImplTestWithParam<MatrixData> {};
 
 TEST_P(MatrixMissingType, Handles_Missing_Type) {
@@ -590,7 +431,7 @@
     EXPECT_FALSE(t.matched);
     ASSERT_EQ(t.value, nullptr);
     ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:8: invalid type for matrix");
+    ASSERT_EQ(p->error(), "1:8: expected expression");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          MatrixMissingType,
diff --git a/src/tint/reader/wgsl/parser_impl_type_decl_without_ident_test.cc b/src/tint/reader/wgsl/parser_impl_type_decl_without_ident_test.cc
deleted file mode 100644
index bd385a6..0000000
--- a/src/tint/reader/wgsl/parser_impl_type_decl_without_ident_test.cc
+++ /dev/null
@@ -1,625 +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/ast/alias.h"
-#include "src/tint/ast/test_helper.h"
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-#include "src/tint/type/sampled_texture.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-using namespace tint::number_suffixes;  // NOLINT
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Invalid) {
-    auto p = parser("1234");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_EQ(t.errored, false);
-    EXPECT_EQ(t.matched, false);
-    EXPECT_EQ(t.value, nullptr);
-    EXPECT_FALSE(p->has_error()) << p->error();
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Identifier) {
-    auto p = parser("A");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_EQ(t.value, nullptr);
-    EXPECT_FALSE(p->has_error()) << p->error();
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Bool) {
-    auto p = parser("bool");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "bool");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_F16) {
-    auto p = parser("f16");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "f16");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_F32) {
-    auto p = parser("f32");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "f32");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_I32) {
-    auto p = parser("i32");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "i32");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_U32) {
-    auto p = parser("u32");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "u32");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
-}
-
-struct VecData {
-    const char* input;
-    size_t count;
-    Source::Range range;
-};
-inline std::ostream& operator<<(std::ostream& out, VecData data) {
-    out << std::string(data.input);
-    return out;
-}
-
-class TypeDeclWithoutIdent_VecTest : public ParserImplTestWithParam<VecData> {};
-
-TEST_P(TypeDeclWithoutIdent_VecTest, Parse) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value,
-                         ast::Template("vec" + std::to_string(params.count), "f32"));
-    EXPECT_EQ(t.value->source.range, params.range);
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         TypeDeclWithoutIdent_VecTest,
-                         testing::Values(VecData{"vec2<f32>", 2, {{1u, 1u}, {1u, 10u}}},
-                                         VecData{"vec3<f32>", 3, {{1u, 1u}, {1u, 10u}}},
-                                         VecData{"vec4<f32>", 4, {{1u, 1u}, {1u, 10u}}}));
-
-class TypeDeclWithoutIdent_VecMissingGreaterThanTest : public ParserImplTestWithParam<VecData> {};
-
-TEST_P(TypeDeclWithoutIdent_VecMissingGreaterThanTest, Handles_Missing_GreaterThan) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:5: missing closing '>' for vector");
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         TypeDeclWithoutIdent_VecMissingGreaterThanTest,
-                         testing::Values(VecData{"vec2<f32", 2, {}},
-                                         VecData{"vec3<f32", 3, {}},
-                                         VecData{"vec4<f32", 4, {}}));
-
-class TypeDeclWithoutIdent_VecMissingType : public ParserImplTestWithParam<VecData> {};
-
-TEST_P(TypeDeclWithoutIdent_VecMissingType, Handles_Missing_Type) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:6: invalid type for vector");
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         TypeDeclWithoutIdent_VecMissingType,
-                         testing::Values(VecData{"vec2<>", 2, {}},
-                                         VecData{"vec3<>", 3, {}},
-                                         VecData{"vec4<>", 4, {}}));
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr) {
-    auto p = parser("ptr<function, f32>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("ptr", "function", "f32"));
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_WithAccess) {
-    auto p = parser("ptr<function, f32, read>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value,
-                         ast::Template("ptr", "function", "f32", "read"));
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_ToVec) {
-    auto p = parser("ptr<function, vec2<f32>>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value,
-                         ast::Template("ptr", "function", ast::Template("vec2", "f32")));
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingLessThan) {
-    auto p = parser("ptr private, f32>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:5: expected '<' for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingGreaterThanAfterType) {
-    auto p = parser("ptr<function, f32");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:4: missing closing '>' for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingGreaterThanAfterAccess) {
-    auto p = parser("ptr<function, f32, read");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:4: missing closing '>' for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingCommaAfterAddressSpace) {
-    auto p = parser("ptr<function f32>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:14: expected ',' for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingCommaAfterAccess) {
-    auto p = parser("ptr<function, f32 read>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingAddressSpace) {
-    auto p = parser("ptr<, f32>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:5: expected address space for ptr declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingType) {
-    auto p = parser("ptr<function,>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:14: invalid type for ptr declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingAccess) {
-    auto p = parser("ptr<function, i32, >");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:20: expected access control for ptr declaration
-Possible values: 'read', 'read_write', 'write')");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingParams) {
-    auto p = parser("ptr<>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:5: expected address space for ptr declaration
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadAddressSpace) {
-    auto p = parser("ptr<unknown, f32>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(),
-              R"(1:5: expected address space for ptr declaration
-Did you mean 'uniform'?
-Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadAccess) {
-    auto p = parser("ptr<function, i32, unknown>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), R"(1:20: expected access control for ptr declaration
-Possible values: 'read', 'read_write', 'write')");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic) {
-    auto p = parser("atomic<f32>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("atomic", "f32"));
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 12u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic_ToVec) {
-    auto p = parser("atomic<vec2<f32>>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value,
-                         ast::Template("atomic", ast::Template("vec2", "f32")));
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic_MissingLessThan) {
-    auto p = parser("atomic f32>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:8: expected '<' for atomic declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic_MissingGreaterThan) {
-    auto p = parser("atomic<f32");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:7: missing closing '>' for atomic declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic_MissingType) {
-    auto p = parser("atomic<>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:8: invalid type for atomic declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_AbstractIntLiteralSize) {
-    auto p = parser("array<f32, 5>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("array", "f32", 5_a));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_SintLiteralSize) {
-    auto p = parser("array<f32, 5i>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("array", "f32", 5_i));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_UintLiteralSize) {
-    auto p = parser("array<f32, 5u>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("array", "f32", 5_u));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_ConstantSize) {
-    auto p = parser("array<f32, size>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("array", "f32", "size"));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_ExpressionSize) {
-    auto p = parser("array<f32, size + 2>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    auto name_for = [&](const Symbol& sym) { return p->builder().Symbols().NameFor(sym); };
-
-    auto* arr = t->expr->identifier->As<ast::TemplatedIdentifier>();
-    EXPECT_EQ(name_for(arr->symbol), "array");
-    EXPECT_TRUE(arr->attributes.IsEmpty());
-
-    ASSERT_EQ(arr->arguments.Length(), 2u);
-
-    auto* ty = As<ast::IdentifierExpression>(arr->arguments[0]);
-    ASSERT_NE(ty, nullptr);
-    EXPECT_EQ(name_for(ty->identifier->symbol), "f32");
-
-    auto* count = As<ast::BinaryExpression>(arr->arguments[1]);
-    ASSERT_NE(count, nullptr);
-    EXPECT_EQ(ast::BinaryOp::kAdd, count->op);
-
-    auto* count_lhs = As<ast::IdentifierExpression>(count->lhs);
-    ASSERT_NE(count_lhs, nullptr);
-    EXPECT_EQ(name_for(count_lhs->identifier->symbol), "size");
-
-    auto* count_rhs = As<ast::IntLiteralExpression>(count->rhs);
-    ASSERT_NE(count_rhs, nullptr);
-    EXPECT_EQ(count_rhs->value, static_cast<int64_t>(2));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_Runtime) {
-    auto p = parser("array<u32>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("array", "u32"));
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 11u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_Runtime_Vec) {
-    auto p = parser("array<vec4<u32>>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value,
-                         ast::Template("array", ast::Template("vec4", "u32")));
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_BadSize) {
-    auto p = parser("array<f32, !>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:13: unable to parse right side of ! expression");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_MissingSize) {
-    auto p = parser("array<f32,>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:11: expected array size expression");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_MissingGreaterThan) {
-    auto p = parser("array<f32");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:6: missing closing '>' for array declaration");
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_MissingComma) {
-    auto p = parser("array<f32 3>");
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration");
-}
-
-struct MatrixData {
-    const char* input;
-    size_t columns;
-    size_t rows;
-    Source::Range range;
-};
-inline std::ostream& operator<<(std::ostream& out, MatrixData data) {
-    out << std::string(data.input);
-    return out;
-}
-
-class TypeDeclWithoutIdent_MatrixTest : public ParserImplTestWithParam<MatrixData> {};
-
-TEST_P(TypeDeclWithoutIdent_MatrixTest, Parse) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ASSERT_FALSE(p->has_error());
-
-    std::string expected_name =
-        "mat" + std::to_string(GetParam().columns) + "x" + std::to_string(GetParam().rows);
-
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template(expected_name, "f32"));
-
-    EXPECT_EQ(t.value->source.range, params.range);
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         TypeDeclWithoutIdent_MatrixTest,
-                         testing::Values(MatrixData{"mat2x2<f32>", 2, 2, {{1u, 1u}, {1u, 12u}}},
-                                         MatrixData{"mat2x3<f32>", 2, 3, {{1u, 1u}, {1u, 12u}}},
-                                         MatrixData{"mat2x4<f32>", 2, 4, {{1u, 1u}, {1u, 12u}}},
-                                         MatrixData{"mat3x2<f32>", 3, 2, {{1u, 1u}, {1u, 12u}}},
-                                         MatrixData{"mat3x3<f32>", 3, 3, {{1u, 1u}, {1u, 12u}}},
-                                         MatrixData{"mat3x4<f32>", 3, 4, {{1u, 1u}, {1u, 12u}}},
-                                         MatrixData{"mat4x2<f32>", 4, 2, {{1u, 1u}, {1u, 12u}}},
-                                         MatrixData{"mat4x3<f32>", 4, 3, {{1u, 1u}, {1u, 12u}}},
-                                         MatrixData{"mat4x4<f32>", 4, 4, {{1u, 1u}, {1u, 12u}}}));
-
-class TypeDeclWithoutIdent_MatrixMissingGreaterThanTest
-    : public ParserImplTestWithParam<MatrixData> {};
-
-TEST_P(TypeDeclWithoutIdent_MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:7: missing closing '>' for matrix");
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         TypeDeclWithoutIdent_MatrixMissingGreaterThanTest,
-                         testing::Values(MatrixData{"mat2x2<f32", 2, 2, {}},
-                                         MatrixData{"mat2x3<f32", 2, 3, {}},
-                                         MatrixData{"mat2x4<f32", 2, 4, {}},
-                                         MatrixData{"mat3x2<f32", 3, 2, {}},
-                                         MatrixData{"mat3x3<f32", 3, 3, {}},
-                                         MatrixData{"mat3x4<f32", 3, 4, {}},
-                                         MatrixData{"mat4x2<f32", 4, 2, {}},
-                                         MatrixData{"mat4x3<f32", 4, 3, {}},
-                                         MatrixData{"mat4x4<f32", 4, 4, {}}));
-
-class TypeDeclWithoutIdent_MatrixMissingType : public ParserImplTestWithParam<MatrixData> {};
-
-TEST_P(TypeDeclWithoutIdent_MatrixMissingType, Handles_Missing_Type) {
-    auto params = GetParam();
-    auto p = parser(params.input);
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.errored);
-    EXPECT_FALSE(t.matched);
-    ASSERT_EQ(t.value, nullptr);
-    ASSERT_TRUE(p->has_error());
-    ASSERT_EQ(p->error(), "1:8: invalid type for matrix");
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         TypeDeclWithoutIdent_MatrixMissingType,
-                         testing::Values(MatrixData{"mat2x2<>", 2, 2, {}},
-                                         MatrixData{"mat2x3<>", 2, 3, {}},
-                                         MatrixData{"mat2x4<>", 2, 4, {}},
-                                         MatrixData{"mat3x2<>", 3, 2, {}},
-                                         MatrixData{"mat3x3<>", 3, 3, {}},
-                                         MatrixData{"mat3x4<>", 3, 4, {}},
-                                         MatrixData{"mat4x2<>", 4, 2, {}},
-                                         MatrixData{"mat4x3<>", 4, 3, {}},
-                                         MatrixData{"mat4x4<>", 4, 4, {}}));
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Sampler) {
-    auto p = parser("sampler");
-
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr) << p->error();
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, "sampler");
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
-}
-
-TEST_F(ParserImplTest, TypeDeclWithoutIdent_Texture) {
-    auto p = parser("texture_cube<f32>");
-
-    auto t = p->type_specifier_without_ident();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_NE(t.value, nullptr);
-    ast::CheckIdentifier(p->builder().Symbols(), t.value, ast::Template("texture_cube", "f32"));
-    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
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 9de2a3d..163396e 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
@@ -38,7 +38,7 @@
     EXPECT_EQ(exp->value, 4u);
 
     ASSERT_TRUE(attr_1->Is<ast::BuiltinAttribute>());
-    EXPECT_EQ(attr_1->As<ast::BuiltinAttribute>()->builtin, ast::BuiltinValue::kPosition);
+    EXPECT_EQ(attr_1->As<ast::BuiltinAttribute>()->builtin, builtin::BuiltinValue::kPosition);
 }
 
 TEST_F(ParserImplTest, AttributeList_Invalid) {
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 602cc20..bc0c2c9 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
@@ -217,7 +217,7 @@
 
 struct BuiltinData {
     const char* input;
-    ast::BuiltinValue result;
+    builtin::BuiltinValue result;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
     out << std::string(data.input);
@@ -261,18 +261,19 @@
 INSTANTIATE_TEST_SUITE_P(
     ParserImplTest,
     BuiltinTest,
-    testing::Values(BuiltinData{"position", ast::BuiltinValue::kPosition},
-                    BuiltinData{"vertex_index", ast::BuiltinValue::kVertexIndex},
-                    BuiltinData{"instance_index", ast::BuiltinValue::kInstanceIndex},
-                    BuiltinData{"front_facing", ast::BuiltinValue::kFrontFacing},
-                    BuiltinData{"frag_depth", ast::BuiltinValue::kFragDepth},
-                    BuiltinData{"local_invocation_id", ast::BuiltinValue::kLocalInvocationId},
-                    BuiltinData{"local_invocation_index", ast::BuiltinValue::kLocalInvocationIndex},
-                    BuiltinData{"global_invocation_id", ast::BuiltinValue::kGlobalInvocationId},
-                    BuiltinData{"workgroup_id", ast::BuiltinValue::kWorkgroupId},
-                    BuiltinData{"num_workgroups", ast::BuiltinValue::kNumWorkgroups},
-                    BuiltinData{"sample_index", ast::BuiltinValue::kSampleIndex},
-                    BuiltinData{"sample_mask", ast::BuiltinValue::kSampleMask}));
+    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}));
 
 TEST_F(ParserImplTest, Attribute_Builtin_MissingLeftParen) {
     auto p = parser("builtin position)");
diff --git a/src/tint/reader/wgsl/parser_impl_vec_mat_prefix_test.cc b/src/tint/reader/wgsl/parser_impl_vec_mat_prefix_test.cc
deleted file mode 100644
index d6204d7..0000000
--- a/src/tint/reader/wgsl/parser_impl_vec_mat_prefix_test.cc
+++ /dev/null
@@ -1,103 +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 {
-
-TEST_F(ParserImplTest, VecPrefix_Vec2) {
-    auto p = parser("vec2");
-    auto t = p->vec_prefix();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    EXPECT_EQ(2u, t.value);
-}
-
-TEST_F(ParserImplTest, VecPrefix_Vec3) {
-    auto p = parser("vec3");
-    auto t = p->vec_prefix();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    EXPECT_EQ(3u, t.value);
-}
-
-TEST_F(ParserImplTest, VecPrefix_Vec4) {
-    auto p = parser("vec4");
-    auto t = p->vec_prefix();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    EXPECT_EQ(4u, t.value);
-}
-
-TEST_F(ParserImplTest, VecPrefix_NoMatch) {
-    auto p = parser("mat2x2");
-    auto t = p->vec_prefix();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    EXPECT_EQ(0u, t.value);
-}
-
-struct MatData {
-    std::string name;
-    uint32_t columns;
-    uint32_t rows;
-};
-class MatPrefixTest : public ParserImplTestWithParam<MatData> {};
-TEST_P(MatPrefixTest, Parse) {
-    auto params = GetParam();
-
-    auto p = parser(params.name);
-    auto t = p->mat_prefix();
-    EXPECT_TRUE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    auto dims = t.value;
-    EXPECT_EQ(params.columns, dims.columns);
-    EXPECT_EQ(params.rows, dims.rows);
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
-                         MatPrefixTest,
-                         testing::Values(MatData{"mat2x2", 2, 2},
-                                         MatData{"mat2x3", 2, 3},
-                                         MatData{"mat2x4", 2, 4},
-                                         MatData{"mat3x2", 3, 2},
-                                         MatData{"mat3x3", 3, 3},
-                                         MatData{"mat3x4", 3, 4},
-                                         MatData{"mat4x2", 4, 2},
-                                         MatData{"mat4x3", 4, 3},
-                                         MatData{"mat4x4", 4, 4}));
-
-TEST_F(ParserImplTest, MatPrefix_NoMatch) {
-    auto p = parser("vec2");
-    auto t = p->mat_prefix();
-    EXPECT_FALSE(t.matched);
-    EXPECT_FALSE(t.errored);
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    EXPECT_EQ(0u, t.value.columns);
-    EXPECT_EQ(0u, t.value.rows);
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc
index 5cc168d..d61843e 100644
--- a/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc
@@ -94,7 +94,7 @@
 // Test a while loop with missing left parenthesis is invalid.
 TEST_F(WhileStmtErrorTest, MissingLeftParen) {
     std::string while_str = "while bool) { }";
-    std::string error_str = "1:11: expected '(' for type initializer";
+    std::string error_str = "1:11: expected '{' for while loop";
 
     TestWhileWithError(while_str, error_str);
 }
diff --git a/src/tint/reader/wgsl/token.cc b/src/tint/reader/wgsl/token.cc
index f13b317..3bc2a0d 100644
--- a/src/tint/reader/wgsl/token.cc
+++ b/src/tint/reader/wgsl/token.cc
@@ -139,14 +139,8 @@
 
         case Token::Type::kAlias:
             return "alias";
-        case Token::Type::kArray:
-            return "array";
-        case Token::Type::kAtomic:
-            return "atomic";
         case Token::Type::kBitcast:
             return "bitcast";
-        case Token::Type::kBool:
-            return "bool";
         case Token::Type::kBreak:
             return "break";
         case Token::Type::kCase:
@@ -169,10 +163,6 @@
             return "else";
         case Token::Type::kEnable:
             return "enable";
-        case Token::Type::kF16:
-            return "f16";
-        case Token::Type::kF32:
-            return "f32";
         case Token::Type::kFallthrough:
             return "fallthrough";
         case Token::Type::kFalse:
@@ -181,96 +171,28 @@
             return "fn";
         case Token::Type::kFor:
             return "for";
-        case Token::Type::kI32:
-            return "i32";
         case Token::Type::kIf:
             return "if";
         case Token::Type::kLet:
             return "let";
         case Token::Type::kLoop:
             return "loop";
-        case Token::Type::kMat2x2:
-            return "mat2x2";
-        case Token::Type::kMat2x3:
-            return "mat2x3";
-        case Token::Type::kMat2x4:
-            return "mat2x4";
-        case Token::Type::kMat3x2:
-            return "mat3x2";
-        case Token::Type::kMat3x3:
-            return "mat3x3";
-        case Token::Type::kMat3x4:
-            return "mat3x4";
-        case Token::Type::kMat4x2:
-            return "mat4x2";
-        case Token::Type::kMat4x3:
-            return "mat4x3";
-        case Token::Type::kMat4x4:
-            return "mat4x4";
         case Token::Type::kOverride:
             return "override";
-        case Token::Type::kPtr:
-            return "ptr";
         case Token::Type::kReturn:
             return "return";
-        case Token::Type::kSampler:
-            return "sampler";
-        case Token::Type::kComparisonSampler:
-            return "sampler_comparison";
         case Token::Type::kStaticAssert:
             return "static_assert";
         case Token::Type::kStruct:
             return "struct";
         case Token::Type::kSwitch:
             return "switch";
-        case Token::Type::kTextureDepth2d:
-            return "texture_depth_2d";
-        case Token::Type::kTextureDepth2dArray:
-            return "texture_depth_2d_array";
-        case Token::Type::kTextureDepthCube:
-            return "texture_depth_cube";
-        case Token::Type::kTextureDepthCubeArray:
-            return "texture_depth_cube_array";
-        case Token::Type::kTextureDepthMultisampled2d:
-            return "texture_depth_multisampled_2d";
-        case Token::Type::kTextureExternal:
-            return "texture_external";
-        case Token::Type::kTextureMultisampled2d:
-            return "texture_multisampled_2d";
-        case Token::Type::kTextureSampled1d:
-            return "texture_1d";
-        case Token::Type::kTextureSampled2d:
-            return "texture_2d";
-        case Token::Type::kTextureSampled2dArray:
-            return "texture_2d_array";
-        case Token::Type::kTextureSampled3d:
-            return "texture_3d";
-        case Token::Type::kTextureSampledCube:
-            return "texture_cube";
-        case Token::Type::kTextureSampledCubeArray:
-            return "texture_cube_array";
-        case Token::Type::kTextureStorage1d:
-            return "texture_storage_1d";
-        case Token::Type::kTextureStorage2d:
-            return "texture_storage_2d";
-        case Token::Type::kTextureStorage2dArray:
-            return "texture_storage_2d_array";
-        case Token::Type::kTextureStorage3d:
-            return "texture_storage_3d";
         case Token::Type::kTrue:
             return "true";
         case Token::Type::kType:
             return "type";
-        case Token::Type::kU32:
-            return "u32";
         case Token::Type::kVar:
             return "var";
-        case Token::Type::kVec2:
-            return "vec2";
-        case Token::Type::kVec3:
-            return "vec3";
-        case Token::Type::kVec4:
-            return "vec4";
         case Token::Type::kWhile:
             return "while";
     }
diff --git a/src/tint/reader/wgsl/token.h b/src/tint/reader/wgsl/token.h
index 7935cc3..c2f08a7 100644
--- a/src/tint/reader/wgsl/token.h
+++ b/src/tint/reader/wgsl/token.h
@@ -151,14 +151,8 @@
 
         /// A 'alias'
         kAlias,
-        /// A 'array'
-        kArray,
-        /// A 'atomic'
-        kAtomic,
         /// A 'bitcast'
         kBitcast,
-        /// A 'bool'
-        kBool,
         /// A 'break'
         kBreak,
         /// A 'case'
@@ -181,10 +175,6 @@
         kElse,
         /// A 'enable'
         kEnable,
-        /// A 'f16'
-        kF16,
-        /// A 'f32'
-        kF32,
         /// A 'fallthrough'
         kFallthrough,
         /// A 'false'
@@ -193,96 +183,28 @@
         kFn,
         // A 'for'
         kFor,
-        /// A 'i32'
-        kI32,
         /// A 'if'
         kIf,
         /// A 'let'
         kLet,
         /// A 'loop'
         kLoop,
-        /// A 'mat2x2'
-        kMat2x2,
-        /// A 'mat2x3'
-        kMat2x3,
-        /// A 'mat2x4'
-        kMat2x4,
-        /// A 'mat3x2'
-        kMat3x2,
-        /// A 'mat3x3'
-        kMat3x3,
-        /// A 'mat3x4'
-        kMat3x4,
-        /// A 'mat4x2'
-        kMat4x2,
-        /// A 'mat4x3'
-        kMat4x3,
-        /// A 'mat4x4'
-        kMat4x4,
         /// A 'override'
         kOverride,
-        /// A 'ptr'
-        kPtr,
         /// A 'return'
         kReturn,
-        /// A 'sampler'
-        kSampler,
-        /// A 'sampler_comparison'
-        kComparisonSampler,
         /// A 'static_assert'
         kStaticAssert,
         /// A 'struct'
         kStruct,
         /// A 'switch'
         kSwitch,
-        /// A 'texture_depth_2d'
-        kTextureDepth2d,
-        /// A 'texture_depth_2d_array'
-        kTextureDepth2dArray,
-        /// A 'texture_depth_cube'
-        kTextureDepthCube,
-        /// A 'texture_depth_cube_array'
-        kTextureDepthCubeArray,
-        /// A 'texture_depth_multisampled_2d'
-        kTextureDepthMultisampled2d,
-        /// A 'texture_external'
-        kTextureExternal,
-        /// A 'texture_multisampled_2d'
-        kTextureMultisampled2d,
-        /// A 'texture_1d'
-        kTextureSampled1d,
-        /// A 'texture_2d'
-        kTextureSampled2d,
-        /// A 'texture_2d_array'
-        kTextureSampled2dArray,
-        /// A 'texture_3d'
-        kTextureSampled3d,
-        /// A 'texture_cube'
-        kTextureSampledCube,
-        /// A 'texture_cube_array'
-        kTextureSampledCubeArray,
-        /// A 'texture_storage_1d'
-        kTextureStorage1d,
-        /// A 'texture_storage_2d'
-        kTextureStorage2d,
-        /// A 'texture_storage_2d_array'
-        kTextureStorage2dArray,
-        /// A 'texture_storage_3d'
-        kTextureStorage3d,
         /// A 'true'
         kTrue,
         /// A 'type'
         kType,
-        /// A 'u32'
-        kU32,
         /// A 'var'
         kVar,
-        /// A 'vec2'
-        kVec2,
-        /// A 'vec3'
-        kVec3,
-        /// A 'vec4'
-        kVec4,
         /// A 'while'
         kWhile,
     };
@@ -359,33 +281,6 @@
                type_ == Type::kFloatLiteral || type_ == Type::kFloatLiteral_F ||
                type_ == Type::kFloatLiteral_H;
     }
-    /// @returns true if token is a 'matNxM'
-    bool IsMatrix() const {
-        return type_ == Type::kMat2x2 || type_ == Type::kMat2x3 || type_ == Type::kMat2x4 ||
-               type_ == Type::kMat3x2 || type_ == Type::kMat3x3 || type_ == Type::kMat3x4 ||
-               type_ == Type::kMat4x2 || type_ == Type::kMat4x3 || type_ == Type::kMat4x4;
-    }
-    /// @returns true if token is a 'mat3xM'
-    bool IsMat3xN() const {
-        return type_ == Type::kMat3x2 || type_ == Type::kMat3x3 || type_ == Type::kMat3x4;
-    }
-    /// @returns true if token is a 'mat4xM'
-    bool IsMat4xN() const {
-        return type_ == Type::kMat4x2 || type_ == Type::kMat4x3 || type_ == Type::kMat4x4;
-    }
-    /// @returns true if token is a 'matNx3'
-    bool IsMatNx3() const {
-        return type_ == Type::kMat2x3 || type_ == Type::kMat3x3 || type_ == Type::kMat4x3;
-    }
-    /// @returns true if token is a 'matNx4'
-    bool IsMatNx4() const {
-        return type_ == Type::kMat2x4 || type_ == Type::kMat3x4 || type_ == Type::kMat4x4;
-    }
-
-    /// @returns true if token is a 'vecN'
-    bool IsVector() const {
-        return type_ == Type::kVec2 || type_ == Type::kVec3 || type_ == Type::kVec4;
-    }
 
     /// @returns the number of placeholder tokens required to follow the token, in order to provide
     /// space for token splitting.
diff --git a/src/tint/resolver/address_space_layout_validation_test.cc b/src/tint/resolver/address_space_layout_validation_test.cc
index 4a2411b..041e566 100644
--- a/src/tint/resolver/address_space_layout_validation_test.cc
+++ b/src/tint/resolver/address_space_layout_validation_test.cc
@@ -371,7 +371,7 @@
     // @group(0) @binding(0)
     // var<uniform> a : ScalarPackedAtEndOfVec3;
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("ScalarPackedAtEndOfVec3", utils::Vector{
                                              Member("v", ty.vec3(ty.f16())),
@@ -568,7 +568,7 @@
     //     @align(1) b : f32;
     // };
     // var<push_constant> a : S;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Structure(
         Source{{12, 34}}, "S",
         utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
@@ -595,7 +595,7 @@
     //     @align(4) b : f32;
     // };
     // var<push_constant> a : S;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    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);
diff --git a/src/tint/resolver/address_space_validation_test.cc b/src/tint/resolver/address_space_validation_test.cc
index f96b29f..2c879de 100644
--- a/src/tint/resolver/address_space_validation_test.cc
+++ b/src/tint/resolver/address_space_validation_test.cc
@@ -249,7 +249,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_F16) {
     // enable f16;
     // var<storage> g : f16;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("g", ty.f16(), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
@@ -259,7 +259,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_F16) {
     // enable f16;
     // type t = ptr<storage, f16>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Alias("t", ty.pointer(ty.f16(), type::AddressSpace::kStorage));
 
@@ -270,7 +270,7 @@
     // enable f16;
     // type a = f16;
     // var<storage, read> g : a;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Alias("a", ty.f16());
     GlobalVar("g", ty("a"), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
@@ -282,7 +282,7 @@
     // enable f16;
     // type a = f16;
     // type t = ptr<storage, a>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Alias("a", ty.f16());
     Alias("t", ty.pointer(ty("a"), type::AddressSpace::kStorage));
@@ -306,7 +306,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_VectorF16) {
     // var<storage> g : vec4<f16>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     GlobalVar("g", ty.vec(ty.f16(), 4u), type::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -314,7 +314,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_VectorF16) {
     // type t = ptr<storage, vec4<f16>>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     Alias("t", ty.pointer(ty.vec(ty.f16(), 4u), type::AddressSpace::kStorage));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -343,7 +343,7 @@
     // enable f16;
     // struct S{ a : f16 };
     // var<storage, read> g : array<S, 3u>;
-    Enable(ast::Extension::kF16);
+    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,
@@ -356,7 +356,7 @@
     // enable f16;
     // struct S{ a : f16 };
     // type t = ptr<storage, read, array<S, 3u>>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("a", ty.f16())});
     Alias("t",
@@ -412,7 +412,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_StructF16) {
     // struct S { x : f16 };
     // var<storage, read> g : S;
-    Enable(ast::Extension::kF16);
+    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),
@@ -424,7 +424,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_StructF16) {
     // struct S { x : f16 };
     // type t = ptr<storage, read, S>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("t", ty.pointer(ty("S"), type::AddressSpace::kStorage, type::Access::kRead));
@@ -436,7 +436,7 @@
     // struct S { x : f16 };
     // type a1 = S;
     // var<storage, read> g : a1;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
@@ -451,7 +451,7 @@
     // struct S { x : f16 };
     // type a1 = S;
     // type t = ptr<storage, read, a1>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
@@ -675,7 +675,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferF16) {
     // enable f16;
     // var<uniform> g : f16;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("g", ty.f16(), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
@@ -685,7 +685,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferF16) {
     // enable f16;
     // type t = ptr<uniform, f16>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Alias("t", ty.pointer(ty.f16(), type::AddressSpace::kUniform));
 
@@ -709,7 +709,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformBufferVectorF16) {
     // enable f16;
     // var<uniform> g : vec4<f16>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
@@ -719,7 +719,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferVectorF16) {
     // enable f16;
     // type t = ptr<uniform, vec4<f16>>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Alias("t", ty.pointer(ty.vec4<f16>(), type::AddressSpace::kUniform));
 
@@ -754,7 +754,7 @@
     //   @size(16) f : f16;
     // }
     // var<uniform> g : array<S, 3u>;
-    Enable(ast::Extension::kF16);
+    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));
@@ -768,7 +768,7 @@
     //   @size(16) f : f16;
     // }
     // type t = ptr<uniform, array<S, 3u>>;
-    Enable(ast::Extension::kF16);
+    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));
@@ -820,7 +820,7 @@
     // enable f16;
     // struct S { x : f16 };
     // var<uniform> g : S;
-    Enable(ast::Extension::kF16);
+    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));
@@ -832,7 +832,7 @@
     // enable f16;
     // struct S { x : f16 };
     // type t = ptr<uniform, S>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("t", ty.pointer(ty("S"), type::AddressSpace::kUniform));
@@ -845,7 +845,7 @@
     // struct S { x : f16 };
     // type a1 = S;
     // var<uniform> g : a1;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
@@ -859,7 +859,7 @@
     // struct S { x : f16 };
     // type a1 = S;
     // type t = ptr<uniform, a1>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
@@ -871,7 +871,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_PushConstantBool) {
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : bool;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar(Source{{56, 78}}, "g", ty.bool_(Source{{12, 34}}), type::AddressSpace::kPushConstant);
 
     ASSERT_FALSE(r()->Resolve());
@@ -884,7 +884,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_PushConstantBool) {
     // enable chromium_experimental_push_constant;
     // type t = ptr<push_constant, bool>;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Alias(Source{{56, 78}}, "t",
           ty.pointer(ty.bool_(Source{{12, 34}}), type::AddressSpace::kPushConstant));
 
@@ -899,8 +899,8 @@
     // enable f16;
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : f16;
-    Enable(ast::Extension::kF16);
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kF16);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar("g", ty.f16(Source{{56, 78}}), type::AddressSpace::kPushConstant);
 
     ASSERT_FALSE(r()->Resolve());
@@ -912,8 +912,8 @@
     // enable f16;
     // enable chromium_experimental_push_constant;
     // type t = ptr<push_constant, f16>;
-    Enable(ast::Extension::kF16);
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kF16);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Alias("t", ty.pointer(ty.f16(Source{{56, 78}}), type::AddressSpace::kPushConstant));
 
     ASSERT_FALSE(r()->Resolve());
@@ -924,7 +924,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_PushConstantPointer) {
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : ptr<private, f32>;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar(Source{{56, 78}}, "g",
               ty.pointer(Source{{12, 34}}, ty.f32(), type::AddressSpace::kPrivate),
               type::AddressSpace::kPushConstant);
@@ -939,7 +939,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_PushConstantPointer) {
     // enable chromium_experimental_push_constant;
     // type t = ptr<push_constant, ptr<private, f32>>;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Alias(Source{{56, 78}}, "t",
           ty.pointer(ty.pointer(Source{{12, 34}}, ty.f32(), type::AddressSpace::kPrivate),
                      type::AddressSpace::kPushConstant));
@@ -954,7 +954,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_PushConstantIntScalar) {
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : i32;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar("g", ty.i32(), type::AddressSpace::kPushConstant);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -963,7 +963,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_PushConstantIntScalar) {
     // enable chromium_experimental_push_constant;
     // type t = ptr<push_constant, i32>;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Alias("t", ty.pointer(ty.i32(), type::AddressSpace::kPushConstant));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -972,7 +972,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_PushConstantVectorF32) {
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : vec4<f32>;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar("g", ty.vec4<f32>(), type::AddressSpace::kPushConstant);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -981,7 +981,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_PushConstantVectorF32) {
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : vec4<f32>;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Alias("t", ty.pointer(ty.vec4<f32>(), type::AddressSpace::kPushConstant));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -991,7 +991,7 @@
     // enable chromium_experimental_push_constant;
     // struct S { a : f32}
     // var<push_constant> g : array<S, 3u>;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Structure("S", utils::Vector{Member("a", ty.f32())});
     GlobalVar("g", ty.array(ty("S"), 3_u), type::AddressSpace::kPushConstant);
 
@@ -1002,7 +1002,7 @@
     // enable chromium_experimental_push_constant;
     // struct S { a : f32}
     // type t = ptr<push_constant, array<S, 3u>>;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    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));
 
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 0f09306..2e4084e 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -95,7 +95,7 @@
         case AttributeKind::kBinding:
             return {builder.Binding(source, 1_a)};
         case AttributeKind::kBuiltin:
-            return {builder.Builtin(source, ast::BuiltinValue::kPosition)};
+            return {builder.Builtin(source, builtin::BuiltinValue::kPosition)};
         case AttributeKind::kDiagnostic:
             return {builder.DiagnosticAttribute(source, ast::DiagnosticSeverity::kInfo,
                                                 "chromium_unreachable_code")};
@@ -257,7 +257,7 @@
     auto& params = GetParam();
     auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
     if (params.kind != AttributeKind::kBuiltin && params.kind != AttributeKind::kLocation) {
-        attrs.Push(Builtin(Source{{34, 56}}, ast::BuiltinValue::kPosition));
+        attrs.Push(Builtin(Source{{34, 56}}, builtin::BuiltinValue::kPosition));
     }
     auto* p = Param("a", ty.vec4<f32>(), attrs);
     Func("frag_main", utils::Vector{p}, ty.void_(), utils::Empty,
@@ -306,7 +306,7 @@
              Stage(ast::PipelineStage::kVertex),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kPosition),
+             Builtin(builtin::BuiltinValue::kPosition),
          });
 
     if (params.should_pass) {
@@ -453,7 +453,7 @@
     auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
     // a vertex shader must include the 'position' builtin in its return type
     if (params.kind != AttributeKind::kBuiltin) {
-        attrs.Push(Builtin(Source{{34, 56}}, ast::BuiltinValue::kPosition));
+        attrs.Push(Builtin(Source{{34, 56}}, builtin::BuiltinValue::kPosition));
     }
     Func("vertex_main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
@@ -654,7 +654,7 @@
                               Member("a", ty.vec4<f32>(),
                                      utils::Vector{
                                          Invariant(),
-                                         Builtin(ast::BuiltinValue::kPosition),
+                                         Builtin(builtin::BuiltinValue::kPosition),
                                      }),
                           });
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1374,7 +1374,7 @@
     auto* param = Param("p", ty.vec4<f32>(),
                         utils::Vector{
                             Invariant(Source{{12, 34}}),
-                            Builtin(Source{{56, 78}}, ast::BuiltinValue::kPosition),
+                            Builtin(Source{{56, 78}}, builtin::BuiltinValue::kPosition),
                         });
     Func("main", utils::Vector{param}, ty.vec4<f32>(),
          utils::Vector{
@@ -1619,7 +1619,7 @@
     auto* s = Structure(
         "S",
         utils::Vector{
-            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
             Member(Source{{12, 34}}, "u", ty.u32(), utils::Vector{Location(0_a)}),
         });
     Func("main", utils::Empty, ty.Of(s),
@@ -1642,7 +1642,7 @@
          utils::Vector{
              Param("a", ty.vec4<f32>(),
                    utils::Vector{
-                       Builtin(ast::BuiltinValue::kPosition),
+                       Builtin(builtin::BuiltinValue::kPosition),
                        Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
                                    ast::InterpolationSampling::kUndefined),
                    }),
@@ -1666,7 +1666,7 @@
              Stage(ast::PipelineStage::kVertex),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kPosition),
+             Builtin(builtin::BuiltinValue::kPosition),
              Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
                          ast::InterpolationSampling::kUndefined),
          });
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index dc49f3a..e3becab 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -471,7 +471,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, OneParam_Scalar_f16) {
     auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto val = 0.5_h;
     if (param.name == std::string("acosh")) {
@@ -499,7 +499,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, OneParam_Vector_f16) {
     auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto val = param.name == std::string("acosh") ? vec3<f16>(1.0_h, 2.0_h, 3.0_h)
                                                   : vec3<f16>(0.5_h, 0.5_h, 0.8_h);
@@ -528,7 +528,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, TwoParams_Scalar_f16) {
     auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call(param.name, 1_h, 1_h);
     WrapInFunction(call);
@@ -551,7 +551,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, TwoParams_Vector_f16) {
     auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
     WrapInFunction(call);
@@ -577,7 +577,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Scalar_f16) {
     auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call(param.name, 0_h, 1_h, 2_h);
     WrapInFunction(call);
@@ -600,7 +600,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Vector_f16) {
     auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call(param.name, vec3<f16>(0_h, 0_h, 0_h), vec3<f16>(1_h, 1_h, 1_h),
                       vec3<f16>(2_h, 2_h, 2_h));
@@ -628,7 +628,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, FourParams_Scalar_f16) {
     auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call(param.name, 1_h, 1_h, 1_h, 1_h);
     WrapInFunction(call);
@@ -651,7 +651,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, FourParams_Vector_f16) {
     auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h),
                       vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
@@ -745,7 +745,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Cross_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("cross", vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(1_h, 2_h, 3_h));
     WrapInFunction(call);
@@ -841,7 +841,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Distance_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("distance", 1_h, 1_h);
     WrapInFunction(call);
@@ -863,7 +863,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Distance_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("distance", vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
     WrapInFunction(call);
@@ -949,7 +949,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, FrexpScalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("frexp", 1_h);
     WrapInFunction(call);
@@ -1013,7 +1013,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, FrexpVector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("frexp", vec3<f16>());
     WrapInFunction(call);
@@ -1075,7 +1075,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Length_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("length", 1_h);
     WrapInFunction(call);
@@ -1097,7 +1097,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Length_FloatVector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("length", vec3<f16>(1_h, 1_h, 3_h));
     WrapInFunction(call);
@@ -1152,7 +1152,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Mix_VectorScalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("mix", vec3<f16>(1_h, 1_h, 1_h), vec3<f16>(1_h, 1_h, 1_h), 4_h);
     WrapInFunction(call);
@@ -1198,7 +1198,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, ModfScalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("modf", 1_h);
     WrapInFunction(call);
@@ -1262,7 +1262,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, ModfVector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("modf", vec3<f16>());
     WrapInFunction(call);
@@ -1372,7 +1372,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Normalize_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* call = Call("normalize", vec3<f16>(1_h, 1_h, 3_h));
     WrapInFunction(call);
@@ -1835,7 +1835,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_2x2_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("var", ty.mat2x2<f16>(), type::AddressSpace::kPrivate);
 
@@ -1861,7 +1861,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_3x3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("var", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
 
@@ -1887,7 +1887,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_4x4_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("var", ty.mat4x4<f16>(), type::AddressSpace::kPrivate);
 
@@ -1948,7 +1948,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Dot_Vec2_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("my_var", ty.vec2<f16>(), type::AddressSpace::kPrivate);
 
diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc
index b9c31c9..22e13c2 100644
--- a/src/tint/resolver/builtin_validation_test.cc
+++ b/src/tint/resolver/builtin_validation_test.cc
@@ -523,7 +523,7 @@
 TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithExtension) {
     // enable chromium_experimental_dp4a;
     // fn func { return dot4I8Packed(1u, 2u); }
-    Enable(ast::Extension::kChromiumExperimentalDp4A);
+    Enable(builtin::Extension::kChromiumExperimentalDp4A);
 
     Func("func", utils::Empty, ty.i32(),
          utils::Vector{
@@ -551,7 +551,7 @@
 TEST_F(ResolverDP4aExtensionValidationTest, Dot4U8PackedWithExtension) {
     // enable chromium_experimental_dp4a;
     // fn func { return dot4U8Packed(1u, 2u); }
-    Enable(ast::Extension::kChromiumExperimentalDp4A);
+    Enable(builtin::Extension::kChromiumExperimentalDp4A);
 
     Func("func", utils::Empty, ty.u32(),
          utils::Vector{
diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc
index 69ab01b..0921c2e 100644
--- a/src/tint/resolver/builtins_validation_test.cc
+++ b/src/tint/resolver/builtins_validation_test.cc
@@ -33,67 +33,79 @@
 namespace StageTest {
 struct Params {
     builder::ast_type_func_ptr type;
-    ast::BuiltinValue builtin;
+    builtin::BuiltinValue builtin;
     ast::PipelineStage stage;
     bool is_valid;
 };
 
 template <typename T>
-constexpr Params ParamsFor(ast::BuiltinValue builtin, ast::PipelineStage stage, bool is_valid) {
+constexpr Params ParamsFor(builtin::BuiltinValue builtin, ast::PipelineStage stage, bool is_valid) {
     return Params{DataType<T>::AST, builtin, stage, is_valid};
 }
 static constexpr Params cases[] = {
-    ParamsFor<vec4<f32>>(ast::BuiltinValue::kPosition, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec4<f32>>(ast::BuiltinValue::kPosition, ast::PipelineStage::kFragment, true),
-    ParamsFor<vec4<f32>>(ast::BuiltinValue::kPosition, ast::PipelineStage::kCompute, false),
+    ParamsFor<vec4<f32>>(builtin::BuiltinValue::kPosition, ast::PipelineStage::kVertex, false),
+    ParamsFor<vec4<f32>>(builtin::BuiltinValue::kPosition, ast::PipelineStage::kFragment, true),
+    ParamsFor<vec4<f32>>(builtin::BuiltinValue::kPosition, ast::PipelineStage::kCompute, false),
 
-    ParamsFor<u32>(ast::BuiltinValue::kVertexIndex, ast::PipelineStage::kVertex, true),
-    ParamsFor<u32>(ast::BuiltinValue::kVertexIndex, ast::PipelineStage::kFragment, false),
-    ParamsFor<u32>(ast::BuiltinValue::kVertexIndex, ast::PipelineStage::kCompute, false),
+    ParamsFor<u32>(builtin::BuiltinValue::kVertexIndex, ast::PipelineStage::kVertex, true),
+    ParamsFor<u32>(builtin::BuiltinValue::kVertexIndex, ast::PipelineStage::kFragment, false),
+    ParamsFor<u32>(builtin::BuiltinValue::kVertexIndex, ast::PipelineStage::kCompute, false),
 
-    ParamsFor<u32>(ast::BuiltinValue::kInstanceIndex, ast::PipelineStage::kVertex, true),
-    ParamsFor<u32>(ast::BuiltinValue::kInstanceIndex, ast::PipelineStage::kFragment, false),
-    ParamsFor<u32>(ast::BuiltinValue::kInstanceIndex, ast::PipelineStage::kCompute, false),
+    ParamsFor<u32>(builtin::BuiltinValue::kInstanceIndex, ast::PipelineStage::kVertex, true),
+    ParamsFor<u32>(builtin::BuiltinValue::kInstanceIndex, ast::PipelineStage::kFragment, false),
+    ParamsFor<u32>(builtin::BuiltinValue::kInstanceIndex, ast::PipelineStage::kCompute, false),
 
-    ParamsFor<bool>(ast::BuiltinValue::kFrontFacing, ast::PipelineStage::kVertex, false),
-    ParamsFor<bool>(ast::BuiltinValue::kFrontFacing, ast::PipelineStage::kFragment, true),
-    ParamsFor<bool>(ast::BuiltinValue::kFrontFacing, ast::PipelineStage::kCompute, false),
+    ParamsFor<bool>(builtin::BuiltinValue::kFrontFacing, ast::PipelineStage::kVertex, false),
+    ParamsFor<bool>(builtin::BuiltinValue::kFrontFacing, ast::PipelineStage::kFragment, true),
+    ParamsFor<bool>(builtin::BuiltinValue::kFrontFacing, ast::PipelineStage::kCompute, false),
 
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kLocalInvocationId, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kLocalInvocationId,
-                         ast::PipelineStage::kFragment,
-                         false),
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kLocalInvocationId, ast::PipelineStage::kCompute, true),
-
-    ParamsFor<u32>(ast::BuiltinValue::kLocalInvocationIndex, ast::PipelineStage::kVertex, false),
-    ParamsFor<u32>(ast::BuiltinValue::kLocalInvocationIndex, ast::PipelineStage::kFragment, false),
-    ParamsFor<u32>(ast::BuiltinValue::kLocalInvocationIndex, ast::PipelineStage::kCompute, true),
-
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kLocalInvocationId,
                          ast::PipelineStage::kVertex,
                          false),
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kLocalInvocationId,
                          ast::PipelineStage::kFragment,
                          false),
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kLocalInvocationId,
                          ast::PipelineStage::kCompute,
                          true),
 
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kWorkgroupId, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kWorkgroupId, ast::PipelineStage::kFragment, false),
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kWorkgroupId, ast::PipelineStage::kCompute, true),
+    ParamsFor<u32>(builtin::BuiltinValue::kLocalInvocationIndex,
+                   ast::PipelineStage::kVertex,
+                   false),
+    ParamsFor<u32>(builtin::BuiltinValue::kLocalInvocationIndex,
+                   ast::PipelineStage::kFragment,
+                   false),
+    ParamsFor<u32>(builtin::BuiltinValue::kLocalInvocationIndex,
+                   ast::PipelineStage::kCompute,
+                   true),
 
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kNumWorkgroups, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kNumWorkgroups, ast::PipelineStage::kFragment, false),
-    ParamsFor<vec3<u32>>(ast::BuiltinValue::kNumWorkgroups, ast::PipelineStage::kCompute, true),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kGlobalInvocationId,
+                         ast::PipelineStage::kVertex,
+                         false),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kGlobalInvocationId,
+                         ast::PipelineStage::kFragment,
+                         false),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kGlobalInvocationId,
+                         ast::PipelineStage::kCompute,
+                         true),
 
-    ParamsFor<u32>(ast::BuiltinValue::kSampleIndex, ast::PipelineStage::kVertex, false),
-    ParamsFor<u32>(ast::BuiltinValue::kSampleIndex, ast::PipelineStage::kFragment, true),
-    ParamsFor<u32>(ast::BuiltinValue::kSampleIndex, ast::PipelineStage::kCompute, false),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kWorkgroupId, ast::PipelineStage::kVertex, false),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kWorkgroupId, ast::PipelineStage::kFragment, false),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kWorkgroupId, ast::PipelineStage::kCompute, true),
 
-    ParamsFor<u32>(ast::BuiltinValue::kSampleMask, ast::PipelineStage::kVertex, false),
-    ParamsFor<u32>(ast::BuiltinValue::kSampleMask, ast::PipelineStage::kFragment, true),
-    ParamsFor<u32>(ast::BuiltinValue::kSampleMask, ast::PipelineStage::kCompute, false),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kNumWorkgroups, ast::PipelineStage::kVertex, false),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kNumWorkgroups,
+                         ast::PipelineStage::kFragment,
+                         false),
+    ParamsFor<vec3<u32>>(builtin::BuiltinValue::kNumWorkgroups, ast::PipelineStage::kCompute, true),
+
+    ParamsFor<u32>(builtin::BuiltinValue::kSampleIndex, ast::PipelineStage::kVertex, false),
+    ParamsFor<u32>(builtin::BuiltinValue::kSampleIndex, ast::PipelineStage::kFragment, true),
+    ParamsFor<u32>(builtin::BuiltinValue::kSampleIndex, ast::PipelineStage::kCompute, false),
+
+    ParamsFor<u32>(builtin::BuiltinValue::kSampleMask, ast::PipelineStage::kVertex, false),
+    ParamsFor<u32>(builtin::BuiltinValue::kSampleMask, ast::PipelineStage::kFragment, true),
+    ParamsFor<u32>(builtin::BuiltinValue::kSampleMask, ast::PipelineStage::kCompute, false),
 };
 
 using ResolverBuiltinsStageTest = ResolverTestWithParam<Params>;
@@ -108,7 +120,7 @@
             Func("main", utils::Vector{input}, ty.vec4<f32>(), utils::Vector{Return(p)},
                  utils::Vector{Stage(ast::PipelineStage::kVertex)},
                  utils::Vector{
-                     Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition),
+                     Builtin(Source{{12, 34}}, builtin::BuiltinValue::kPosition),
                  });
             break;
         case ast::PipelineStage::kFragment:
@@ -152,7 +164,7 @@
          utils::Vector{
              Param("fd", ty.f32(),
                    utils::Vector{
-                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth),
+                       Builtin(Source{{12, 34}}, builtin::BuiltinValue::kFragDepth),
                    }),
          },
          ty.f32(),
@@ -182,7 +194,7 @@
                         utils::Vector{
                             Member("frag_depth", ty.f32(),
                                    utils::Vector{
-                                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth),
+                                       Builtin(Source{{12, 34}}, builtin::BuiltinValue::kFragDepth),
                                    }),
                         });
 
@@ -217,7 +229,7 @@
     Structure("S", utils::Vector{
                        Member("idx", ty.u32(),
                               utils::Vector{
-                                  Builtin(ast::BuiltinValue::kVertexIndex),
+                                  Builtin(builtin::BuiltinValue::kVertexIndex),
                               }),
                    });
 
@@ -241,7 +253,7 @@
                         utils::Vector{
                             Member("position", ty.vec4<u32>(),
                                    utils::Vector{
-                                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition),
+                                       Builtin(Source{{12, 34}}, builtin::BuiltinValue::kPosition),
                                    }),
                         });
     Func("fragShader",
@@ -272,7 +284,7 @@
          },
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
          utils::Vector{
-             Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition),
+             Builtin(Source{{12, 34}}, builtin::BuiltinValue::kPosition),
          });
 
     EXPECT_FALSE(r()->Resolve());
@@ -290,7 +302,7 @@
                         utils::Vector{
                             Member("frag_depth", ty.i32(),
                                    utils::Vector{
-                                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth),
+                                       Builtin(Source{{12, 34}}, builtin::BuiltinValue::kFragDepth),
                                    }),
                         });
     Func("fragShader", utils::Vector{Param("arg", ty.Of(s))}, ty.f32(),
@@ -315,13 +327,13 @@
     // @fragment
     // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-    auto* s = Structure("MyInputs",
-                        utils::Vector{
-                            Member("m", ty.f32(),
-                                   utils::Vector{
-                                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask),
-                                   }),
-                        });
+    auto* s = Structure(
+        "MyInputs", utils::Vector{
+                        Member("m", ty.f32(),
+                               utils::Vector{
+                                   Builtin(Source{{12, 34}}, builtin::BuiltinValue::kSampleMask),
+                               }),
+                    });
     Func("fragShader", utils::Vector{Param("arg", ty.Of(s))}, ty.f32(),
          utils::Vector{
              Return(1_f),
@@ -345,7 +357,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask),
+             Builtin(Source{{12, 34}}, builtin::BuiltinValue::kSampleMask),
          });
 
     EXPECT_FALSE(r()->Resolve());
@@ -361,7 +373,7 @@
          utils::Vector{
              Param("arg", ty.bool_(),
                    utils::Vector{
-                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask),
+                       Builtin(Source{{12, 34}}, builtin::BuiltinValue::kSampleMask),
                    }),
          },
          ty.f32(),
@@ -385,13 +397,13 @@
     // @fragment
     // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-    auto* s = Structure("MyInputs",
-                        utils::Vector{
-                            Member("m", ty.f32(),
-                                   utils::Vector{
-                                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleIndex),
-                                   }),
-                        });
+    auto* s = Structure(
+        "MyInputs", utils::Vector{
+                        Member("m", ty.f32(),
+                               utils::Vector{
+                                   Builtin(Source{{12, 34}}, builtin::BuiltinValue::kSampleIndex),
+                               }),
+                    });
     Func("fragShader", utils::Vector{Param("arg", ty.Of(s))}, ty.f32(),
          utils::Vector{
              Return(1_f),
@@ -416,7 +428,7 @@
          utils::Vector{
              Param("arg", ty.bool_(),
                    utils::Vector{
-                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleIndex),
+                       Builtin(Source{{12, 34}}, builtin::BuiltinValue::kSampleIndex),
                    }),
          },
          ty.f32(),
@@ -442,7 +454,7 @@
          utils::Vector{
              Param("p", ty.vec3<f32>(),
                    utils::Vector{
-                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition),
+                       Builtin(Source{{12, 34}}, builtin::BuiltinValue::kPosition),
                    }),
          },
          ty.f32(),
@@ -472,7 +484,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth),
+             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'");
@@ -486,18 +498,18 @@
     // ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
     auto* p = Param("p", ty.vec4<f32>(),
                     utils::Vector{
-                        Builtin(ast::BuiltinValue::kPosition),
+                        Builtin(builtin::BuiltinValue::kPosition),
                     });
     auto* vi = Param("vi", ty.f32(),
                      utils::Vector{
-                         Builtin(Source{{12, 34}}, ast::BuiltinValue::kVertexIndex),
+                         Builtin(Source{{12, 34}}, builtin::BuiltinValue::kVertexIndex),
                      });
     Func("main", utils::Vector{vi, p}, ty.vec4<f32>(), utils::Vector{Return(Expr("p"))},
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kPosition),
+             Builtin(builtin::BuiltinValue::kPosition),
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(vertex_index) must be 'u32'");
@@ -511,18 +523,18 @@
     // ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
     auto* p = Param("p", ty.vec4<f32>(),
                     utils::Vector{
-                        Builtin(ast::BuiltinValue::kPosition),
+                        Builtin(builtin::BuiltinValue::kPosition),
                     });
     auto* ii = Param("ii", ty.f32(),
                      utils::Vector{
-                         Builtin(Source{{12, 34}}, ast::BuiltinValue::kInstanceIndex),
+                         Builtin(Source{{12, 34}}, builtin::BuiltinValue::kInstanceIndex),
                      });
     Func("main", utils::Vector{ii, p}, ty.vec4<f32>(), utils::Vector{Return(Expr("p"))},
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kPosition),
+             Builtin(builtin::BuiltinValue::kPosition),
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(instance_index) must be 'u32'");
@@ -538,19 +550,19 @@
     // ) -> @builtin(frag_depth) f32 { var fd: f32; return fd; }
     auto* p = Param("p", ty.vec4<f32>(),
                     utils::Vector{
-                        Builtin(ast::BuiltinValue::kPosition),
+                        Builtin(builtin::BuiltinValue::kPosition),
                     });
     auto* ff = Param("ff", ty.bool_(),
                      utils::Vector{
-                         Builtin(ast::BuiltinValue::kFrontFacing),
+                         Builtin(builtin::BuiltinValue::kFrontFacing),
                      });
     auto* si = Param("si", ty.u32(),
                      utils::Vector{
-                         Builtin(ast::BuiltinValue::kSampleIndex),
+                         Builtin(builtin::BuiltinValue::kSampleIndex),
                      });
     auto* sm = Param("sm", ty.u32(),
                      utils::Vector{
-                         Builtin(ast::BuiltinValue::kSampleMask),
+                         Builtin(builtin::BuiltinValue::kSampleMask),
                      });
     auto* var_fd = Var("fd", ty.f32());
     Func("fs_main", utils::Vector{p, ff, si, sm}, ty.f32(),
@@ -562,7 +574,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kFragDepth),
+             Builtin(builtin::BuiltinValue::kFragDepth),
          });
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -575,12 +587,12 @@
     // ) -> @builtin(position) vec4<f32> { var p :vec4<f32>; return p; }
     auto* vi = Param("vi", ty.u32(),
                      utils::Vector{
-                         Builtin(Source{{12, 34}}, ast::BuiltinValue::kVertexIndex),
+                         Builtin(Source{{12, 34}}, builtin::BuiltinValue::kVertexIndex),
                      });
 
     auto* ii = Param("ii", ty.u32(),
                      utils::Vector{
-                         Builtin(Source{{12, 34}}, ast::BuiltinValue::kInstanceIndex),
+                         Builtin(Source{{12, 34}}, builtin::BuiltinValue::kInstanceIndex),
                      });
     auto* p = Var("p", ty.vec4<f32>());
     Func("main", utils::Vector{vi, ii}, ty.vec4<f32>(),
@@ -590,7 +602,7 @@
          },
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
          utils::Vector{
-             Builtin(ast::BuiltinValue::kPosition),
+             Builtin(builtin::BuiltinValue::kPosition),
          });
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -608,23 +620,23 @@
 
     auto* li_id = Param("li_id", ty.vec3<u32>(),
                         utils::Vector{
-                            Builtin(ast::BuiltinValue::kLocalInvocationId),
+                            Builtin(builtin::BuiltinValue::kLocalInvocationId),
                         });
     auto* li_index = Param("li_index", ty.u32(),
                            utils::Vector{
-                               Builtin(ast::BuiltinValue::kLocalInvocationIndex),
+                               Builtin(builtin::BuiltinValue::kLocalInvocationIndex),
                            });
     auto* gi = Param("gi", ty.vec3<u32>(),
                      utils::Vector{
-                         Builtin(ast::BuiltinValue::kGlobalInvocationId),
+                         Builtin(builtin::BuiltinValue::kGlobalInvocationId),
                      });
     auto* wi = Param("wi", ty.vec3<u32>(),
                      utils::Vector{
-                         Builtin(ast::BuiltinValue::kWorkgroupId),
+                         Builtin(builtin::BuiltinValue::kWorkgroupId),
                      });
     auto* nwgs = Param("nwgs", ty.vec3<u32>(),
                        utils::Vector{
-                           Builtin(ast::BuiltinValue::kNumWorkgroups),
+                           Builtin(builtin::BuiltinValue::kNumWorkgroups),
                        });
 
     Func("main", utils::Vector{li_id, li_index, gi, wi, nwgs}, ty.void_(), utils::Empty,
@@ -637,7 +649,7 @@
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_WorkGroupIdNotVec3U32) {
     auto* wi = Param("wi", ty.f32(),
                      utils::Vector{
-                         Builtin(Source{{12, 34}}, ast::BuiltinValue::kWorkgroupId),
+                         Builtin(Source{{12, 34}}, builtin::BuiltinValue::kWorkgroupId),
                      });
     Func("main", utils::Vector{wi}, ty.void_(), utils::Empty,
          utils::Vector{Stage(ast::PipelineStage::kCompute),
@@ -652,7 +664,7 @@
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_NumWorkgroupsNotVec3U32) {
     auto* nwgs = Param("nwgs", ty.f32(),
                        utils::Vector{
-                           Builtin(Source{{12, 34}}, ast::BuiltinValue::kNumWorkgroups),
+                           Builtin(Source{{12, 34}}, builtin::BuiltinValue::kNumWorkgroups),
                        });
     Func("main", utils::Vector{nwgs}, ty.void_(), utils::Empty,
          utils::Vector{Stage(ast::PipelineStage::kCompute),
@@ -667,7 +679,7 @@
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_GlobalInvocationNotVec3U32) {
     auto* gi = Param("gi", ty.vec3<i32>(),
                      utils::Vector{
-                         Builtin(Source{{12, 34}}, ast::BuiltinValue::kGlobalInvocationId),
+                         Builtin(Source{{12, 34}}, builtin::BuiltinValue::kGlobalInvocationId),
                      });
     Func("main", utils::Vector{gi}, ty.void_(), utils::Empty,
          utils::Vector{Stage(ast::PipelineStage::kCompute),
@@ -680,10 +692,11 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationIndexNotU32) {
-    auto* li_index = Param("li_index", ty.vec3<u32>(),
-                           utils::Vector{
-                               Builtin(Source{{12, 34}}, ast::BuiltinValue::kLocalInvocationIndex),
-                           });
+    auto* li_index =
+        Param("li_index", ty.vec3<u32>(),
+              utils::Vector{
+                  Builtin(Source{{12, 34}}, builtin::BuiltinValue::kLocalInvocationIndex),
+              });
     Func("main", utils::Vector{li_index}, ty.void_(), utils::Empty,
          utils::Vector{Stage(ast::PipelineStage::kCompute),
                        WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
@@ -697,7 +710,7 @@
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationNotVec3U32) {
     auto* li_id = Param("li_id", ty.vec2<u32>(),
                         utils::Vector{
-                            Builtin(Source{{12, 34}}, ast::BuiltinValue::kLocalInvocationId),
+                            Builtin(Source{{12, 34}}, builtin::BuiltinValue::kLocalInvocationId),
                         });
     Func("main", utils::Vector{li_id}, ty.void_(), utils::Empty,
          utils::Vector{Stage(ast::PipelineStage::kCompute),
@@ -722,19 +735,19 @@
     auto* s = Structure("MyInputs", utils::Vector{
                                         Member("position", ty.vec4<f32>(),
                                                utils::Vector{
-                                                   Builtin(ast::BuiltinValue::kPosition),
+                                                   Builtin(builtin::BuiltinValue::kPosition),
                                                }),
                                         Member("front_facing", ty.bool_(),
                                                utils::Vector{
-                                                   Builtin(ast::BuiltinValue::kFrontFacing),
+                                                   Builtin(builtin::BuiltinValue::kFrontFacing),
                                                }),
                                         Member("sample_index", ty.u32(),
                                                utils::Vector{
-                                                   Builtin(ast::BuiltinValue::kSampleIndex),
+                                                   Builtin(builtin::BuiltinValue::kSampleIndex),
                                                }),
                                         Member("sample_mask", ty.u32(),
                                                utils::Vector{
-                                                   Builtin(ast::BuiltinValue::kSampleMask),
+                                                   Builtin(builtin::BuiltinValue::kSampleMask),
                                                }),
                                     });
     Func("fragShader", utils::Vector{Param("arg", ty.Of(s))}, ty.f32(),
@@ -758,7 +771,7 @@
 
     auto* is_front = Param("is_front", ty.i32(),
                            utils::Vector{
-                               Builtin(Source{{12, 34}}, ast::BuiltinValue::kFrontFacing),
+                               Builtin(Source{{12, 34}}, builtin::BuiltinValue::kFrontFacing),
                            });
     Func("fs_main", utils::Vector{is_front}, ty.f32(),
          utils::Vector{
@@ -782,13 +795,13 @@
     // @fragment
     // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-    auto* s = Structure("MyInputs",
-                        utils::Vector{
-                            Member("pos", ty.f32(),
-                                   utils::Vector{
-                                       Builtin(Source{{12, 34}}, ast::BuiltinValue::kFrontFacing),
-                                   }),
-                        });
+    auto* s = Structure(
+        "MyInputs", utils::Vector{
+                        Member("pos", ty.f32(),
+                               utils::Vector{
+                                   Builtin(Source{{12, 34}}, builtin::BuiltinValue::kFrontFacing),
+                               }),
+                    });
     Func("fragShader", utils::Vector{Param("is_front", ty.Of(s))}, ty.f32(),
          utils::Vector{
              Return(1_f),
diff --git a/src/tint/resolver/call_test.cc b/src/tint/resolver/call_test.cc
index e5b245c..25f4814 100644
--- a/src/tint/resolver/call_test.cc
+++ b/src/tint/resolver/call_test.cc
@@ -82,7 +82,7 @@
 };
 
 TEST_F(ResolverCallTest, Valid) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     utils::Vector<const ast::Parameter*, 4> params;
     utils::Vector<const ast::Expression*, 4> args;
diff --git a/src/tint/resolver/call_validation_test.cc b/src/tint/resolver/call_validation_test.cc
index 07e2271..b0b8cce 100644
--- a/src/tint/resolver/call_validation_test.cc
+++ b/src/tint/resolver/call_validation_test.cc
@@ -165,7 +165,7 @@
     //   var v : S;
     //   foo(&v.m);
     // }
-    Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
+    Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     auto* S = Structure("S", utils::Vector{
                                  Member("m", ty.i32()),
                              });
@@ -346,7 +346,7 @@
     //   let p: ptr<function, i32> = &(v[0]);
     //   x(p);
     // }
-    Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
+    Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     Func("foo",
          utils::Vector{
              Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
@@ -437,7 +437,7 @@
     //   let p3 = &(*p2)[0];
     //   foo(&*p);
     // }
-    Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
+    Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     Func("foo",
          utils::Vector{
              Param("p", ty.pointer<i32>(type::AddressSpace::kFunction)),
diff --git a/src/tint/resolver/const_eval_binary_op_test.cc b/src/tint/resolver/const_eval_binary_op_test.cc
index e7f6f14..ef7453e 100644
--- a/src/tint/resolver/const_eval_binary_op_test.cc
+++ b/src/tint/resolver/const_eval_binary_op_test.cc
@@ -83,7 +83,7 @@
 
 using ResolverConstEvalBinaryOpTest = ResolverTestWithParam<std::tuple<ast::BinaryOp, Case>>;
 TEST_P(ResolverConstEvalBinaryOpTest, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto op = std::get<0>(GetParam());
     auto& c = std::get<1>(GetParam());
 
diff --git a/src/tint/resolver/const_eval_builtin_test.cc b/src/tint/resolver/const_eval_builtin_test.cc
index 76f8238..4e3cb5a 100644
--- a/src/tint/resolver/const_eval_builtin_test.cc
+++ b/src/tint/resolver/const_eval_builtin_test.cc
@@ -142,7 +142,7 @@
 using ResolverConstEvalBuiltinTest = ResolverTestWithParam<std::tuple<sem::BuiltinType, Case>>;
 
 TEST_P(ResolverConstEvalBuiltinTest, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto builtin = std::get<0>(GetParam());
     auto& c = std::get<1>(GetParam());
diff --git a/src/tint/resolver/const_eval_construction_test.cc b/src/tint/resolver/const_eval_construction_test.cc
index fbf7515..55c2cf5 100644
--- a/src/tint/resolver/const_eval_construction_test.cc
+++ b/src/tint/resolver/const_eval_construction_test.cc
@@ -102,7 +102,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = Expr(9.9_h);
     WrapInFunction(expr);
@@ -146,7 +146,7 @@
 }
 using ResolverConstEvalZeroInitTest = ResolverTestWithParam<Case>;
 TEST_P(ResolverConstEvalZeroInitTest, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto& param = GetParam();
     auto ty = param.type(*this);
     auto* expr = Call(ty);
@@ -316,7 +316,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>();
     WrapInFunction(expr);
@@ -483,7 +483,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Splat_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(9.9_h);
     WrapInFunction(expr);
@@ -719,7 +719,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(1_h, 2_h, 3_h);
     WrapInFunction(expr);
@@ -1018,7 +1018,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(1_h, vec2<f16>(2_h, 3_h));
     WrapInFunction(expr);
@@ -1053,7 +1053,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_10) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(10_h, vec2<f16>(10_h, 10_h));
     WrapInFunction(expr);
@@ -1088,7 +1088,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_positive_0) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(0_h, vec2<f16>(0_h, 0_h));
     WrapInFunction(expr);
@@ -1123,7 +1123,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_negative_0) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(vec2<f16>(-0_h, -0_h), -0_h);
     WrapInFunction(expr);
@@ -1158,7 +1158,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_mixed_sign_0) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(0_h, vec2<f16>(-0_h, 0_h));
     WrapInFunction(expr);
@@ -1341,7 +1341,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Mat2x3_ZeroInit_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = mat2x3<f16>();
     WrapInFunction(expr);
@@ -1704,7 +1704,7 @@
 
 using ResolverConstEvalArrayInitTest = ResolverTestWithParam<Case>;
 TEST_P(ResolverConstEvalArrayInitTest, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto& param = GetParam();
     auto* expr = param.input.Expr(*this);
     auto* a = Const("a", expr);
@@ -1892,7 +1892,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Struct_ZeroInit) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto* s = Structure("S", utils::Vector{
                                  Member("a", ty.i32()),
                                  Member("b", ty.u32()),
@@ -1937,7 +1937,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Struct_Nested_ZeroInit) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto* inner = Structure("Inner", utils::Vector{
                                          Member("a", ty.i32()),
                                          Member("b", ty.u32()),
@@ -2028,7 +2028,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Struct_MixedScalars_ZeroInit) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{
                        Member("m1", ty.i32()),
@@ -2138,7 +2138,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Struct_MixedVectors_ZeroInit) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{
                        Member("m1", ty.vec2<i32>()),
@@ -2258,7 +2258,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Struct_MixedScalars_Construct) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{
                        Member("m1", ty.i32()),
@@ -2315,7 +2315,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Struct_MixedVectors_Construct) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{
                        Member("m1", ty.vec2<i32>()),
diff --git a/src/tint/resolver/const_eval_conversion_test.cc b/src/tint/resolver/const_eval_conversion_test.cc
index e159b0e..bcad648 100644
--- a/src/tint/resolver/const_eval_conversion_test.cc
+++ b/src/tint/resolver/const_eval_conversion_test.cc
@@ -289,7 +289,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_f16_to_i32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<i32>(vec3<f16>(1.1_h, 2.2_h, 3.3_h));
     WrapInFunction(expr);
@@ -324,7 +324,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_u32_to_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(vec3<u32>(10_u, 20_u, 30_u));
     WrapInFunction(expr);
@@ -425,7 +425,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(Source{{12, 34}}, vec3<f32>(1e10_f, 0_f, 0_f));
     WrapInFunction(expr);
@@ -435,7 +435,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_Small_f32_to_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = vec3<f16>(vec3<f32>(1e-20_f, -2e-30_f, 3e-40_f));
     WrapInFunction(expr);
diff --git a/src/tint/resolver/const_eval_indexing_test.cc b/src/tint/resolver/const_eval_indexing_test.cc
index 9776674..cfd7aa1 100644
--- a/src/tint/resolver/const_eval_indexing_test.cc
+++ b/src/tint/resolver/const_eval_indexing_test.cc
@@ -68,7 +68,7 @@
 
 using ResolverConstEvalSwizzleTest = ResolverTestWithParam<Case>;
 TEST_P(ResolverConstEvalSwizzleTest, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto& param = GetParam();
     auto* expr = MemberAccessor(param.input.Expr(*this), param.swizzle);
     auto* a = Const("a", expr);
diff --git a/src/tint/resolver/const_eval_member_access_test.cc b/src/tint/resolver/const_eval_member_access_test.cc
index e93d63b..4fcba8b 100644
--- a/src/tint/resolver/const_eval_member_access_test.cc
+++ b/src/tint/resolver/const_eval_member_access_test.cc
@@ -263,7 +263,7 @@
 
 using ResolverConstEvalArrayAccessTest = ResolverTestWithParam<Case>;
 TEST_P(ResolverConstEvalArrayAccessTest, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto& param = GetParam();
     auto* expr = param.input.Expr(*this);
@@ -338,7 +338,7 @@
 
 using ResolverConstEvalVectorAccessTest = ResolverTestWithParam<Case>;
 TEST_P(ResolverConstEvalVectorAccessTest, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto& param = GetParam();
     auto* expr = param.input.Expr(*this);
diff --git a/src/tint/resolver/const_eval_unary_op_test.cc b/src/tint/resolver/const_eval_unary_op_test.cc
index f9a1e57..8b9b7c8 100644
--- a/src/tint/resolver/const_eval_unary_op_test.cc
+++ b/src/tint/resolver/const_eval_unary_op_test.cc
@@ -42,7 +42,7 @@
 using ResolverConstEvalUnaryOpTest = ResolverTestWithParam<std::tuple<ast::UnaryOp, Case>>;
 
 TEST_P(ResolverConstEvalUnaryOpTest, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto op = std::get<0>(GetParam());
     auto& c = std::get<1>(GetParam());
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index 8d61599..31e484e 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -1094,7 +1094,7 @@
     // a transform may produce such a AST tree that has some declarations before directive nodes.
     // DependencyGraph should deal with these cases.
     auto* var_1 = GlobalVar("SYMBOL1", ty.i32());
-    auto* enable = Enable(ast::Extension::kF16);
+    auto* enable = Enable(builtin::Extension::kF16);
     auto* var_2 = GlobalVar("SYMBOL2", ty.f32());
     auto* diagnostic = DiagnosticDirective(ast::DiagnosticSeverity::kWarning, "foo");
 
diff --git a/src/tint/resolver/entry_point_validation_test.cc b/src/tint/resolver/entry_point_validation_test.cc
index 2ca3e93..98012ad 100644
--- a/src/tint/resolver/entry_point_validation_test.cc
+++ b/src/tint/resolver/entry_point_validation_test.cc
@@ -74,7 +74,7 @@
              Stage(ast::PipelineStage::kVertex),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kPosition),
+             Builtin(builtin::BuiltinValue::kPosition),
          });
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -111,7 +111,7 @@
          },
          utils::Vector{
              Location(Source{{13, 43}}, 0_a),
-             Builtin(Source{{14, 52}}, ast::BuiltinValue::kPosition),
+             Builtin(Source{{14, 52}}, builtin::BuiltinValue::kPosition),
          });
 
     EXPECT_FALSE(r()->Resolve());
@@ -129,10 +129,11 @@
     //   return Output();
     // }
     auto* output = Structure(
-        "Output", utils::Vector{
-                      Member("a", ty.f32(), utils::Vector{Location(0_a)}),
-                      Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
-                  });
+        "Output",
+        utils::Vector{
+            Member("a", ty.f32(), utils::Vector{Location(0_a)}),
+            Member("b", ty.f32(), utils::Vector{Builtin(builtin::BuiltinValue::kFragDepth)}),
+        });
     Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
          utils::Vector{
              Return(Call(ty.Of(output))),
@@ -157,7 +158,7 @@
         utils::Vector{
             Member("a", ty.f32(),
                    utils::Vector{Location(Source{{13, 43}}, 0_a),
-                                 Builtin(Source{{14, 52}}, ast::BuiltinValue::kFragDepth)}),
+                                 Builtin(Source{{14, 52}}, builtin::BuiltinValue::kFragDepth)}),
         });
     Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
          utils::Vector{
@@ -211,10 +212,11 @@
     //   return Output();
     // }
     auto* output = Structure(
-        "Output", utils::Vector{
-                      Member("a", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
-                      Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
-                  });
+        "Output",
+        utils::Vector{
+            Member("a", ty.f32(), utils::Vector{Builtin(builtin::BuiltinValue::kFragDepth)}),
+            Member("b", ty.f32(), utils::Vector{Builtin(builtin::BuiltinValue::kFragDepth)}),
+        });
     Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
          utils::Vector{
              Return(Call(ty.Of(output))),
@@ -272,7 +274,7 @@
     auto* param = Param("param", ty.u32(),
                         utils::Vector{
                             Location(Source{{13, 43}}, 0_a),
-                            Builtin(Source{{14, 52}}, ast::BuiltinValue::kSampleIndex),
+                            Builtin(Source{{14, 52}}, builtin::BuiltinValue::kSampleIndex),
                         });
     Func(Source{{12, 34}}, "main",
          utils::Vector{
@@ -296,10 +298,11 @@
     // @fragment
     // fn main(param : Input) {}
     auto* input = Structure(
-        "Input", utils::Vector{
-                     Member("a", ty.f32(), utils::Vector{Location(0_a)}),
-                     Member("b", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
-                 });
+        "Input",
+        utils::Vector{
+            Member("a", ty.f32(), utils::Vector{Location(0_a)}),
+            Member("b", ty.u32(), utils::Vector{Builtin(builtin::BuiltinValue::kSampleIndex)}),
+        });
     auto* param = Param("param", ty.Of(input));
     Func(Source{{12, 34}}, "main",
          utils::Vector{
@@ -324,7 +327,7 @@
         utils::Vector{
             Member("a", ty.u32(),
                    utils::Vector{Location(Source{{13, 43}}, 0_a),
-                                 Builtin(Source{{14, 52}}, ast::BuiltinValue::kSampleIndex)}),
+                                 Builtin(Source{{14, 52}}, builtin::BuiltinValue::kSampleIndex)}),
         });
     auto* param = Param("param", ty.Of(input));
     Func(Source{{12, 34}}, "main",
@@ -375,11 +378,11 @@
     //         @builtin(sample_index) param_b : u32) {}
     auto* param_a = Param("param_a", ty.u32(),
                           utils::Vector{
-                              Builtin(ast::BuiltinValue::kSampleIndex),
+                              Builtin(builtin::BuiltinValue::kSampleIndex),
                           });
     auto* param_b = Param("param_b", ty.u32(),
                           utils::Vector{
-                              Builtin(ast::BuiltinValue::kSampleIndex),
+                              Builtin(builtin::BuiltinValue::kSampleIndex),
                           });
     Func(Source{{12, 34}}, "main",
          utils::Vector{
@@ -409,12 +412,12 @@
     auto* input_a = Structure(
         "InputA",
         utils::Vector{
-            Member("a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+            Member("a", ty.u32(), utils::Vector{Builtin(builtin::BuiltinValue::kSampleIndex)}),
         });
     auto* input_b = Structure(
         "InputB",
         utils::Vector{
-            Member("a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
+            Member("a", ty.u32(), utils::Vector{Builtin(builtin::BuiltinValue::kSampleIndex)}),
         });
     auto* param_a = Param("param_a", ty.Of(input_a));
     auto* param_b = Param("param_b", ty.Of(input_b));
@@ -452,7 +455,7 @@
 TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithEnable) {
     // enable chromium_experimental_push_constant;
     // var<push_constant> a : u32;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar("a", ty.u32(), type::AddressSpace::kPushConstant);
 
     EXPECT_TRUE(r()->Resolve());
@@ -482,7 +485,7 @@
     // @compute @workgroup_size(1) fn main() {
     //   _ = a;
     // }
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar("a", ty.u32(), type::AddressSpace::kPushConstant);
 
     Func("main", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
@@ -500,7 +503,7 @@
     //   _ = a;
     //   _ = b;
     // }
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar(Source{{1, 2}}, "a", ty.u32(), type::AddressSpace::kPushConstant);
     GlobalVar(Source{{3, 4}}, "b", ty.u32(), type::AddressSpace::kPushConstant);
 
@@ -531,7 +534,7 @@
     //   uses_a();
     //   uses_b();
     // }
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar(Source{{1, 2}}, "a", ty.u32(), type::AddressSpace::kPushConstant);
     GlobalVar(Source{{3, 4}}, "b", ty.u32(), type::AddressSpace::kPushConstant);
 
@@ -564,7 +567,7 @@
     // @compute @workgroup_size(1) fn uses_b() {
     //   _ = a;
     // }
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar("a", ty.u32(), type::AddressSpace::kPushConstant);
     GlobalVar("b", ty.u32(), type::AddressSpace::kPushConstant);
 
@@ -621,7 +624,7 @@
     // fn main(@location(0) @interpolate(flat) a : *) {}
     auto params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* a = Param("a", params.create_ast_type(*this),
                     utils::Vector{
@@ -652,7 +655,7 @@
     // fn main(a : Input) {}
     auto params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* input = Structure("Input", utils::Vector{
                                          Member("a", params.create_ast_type(*this),
@@ -682,7 +685,7 @@
     // }
     auto params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Func(Source{{12, 34}}, "main", utils::Empty, params.create_ast_type(*this),
          utils::Vector{
@@ -712,7 +715,7 @@
     // }
     auto params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* output = Structure(
         "Output", utils::Vector{
@@ -984,10 +987,11 @@
     //   return Output();
     // }
     auto* output = Structure(
-        "Output", utils::Vector{
-                      Member("a", ty.f32(), utils::Vector{Location(0_a)}),
-                      Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
-                  });
+        "Output",
+        utils::Vector{
+            Member("a", ty.f32(), utils::Vector{Location(0_a)}),
+            Member("b", ty.f32(), utils::Vector{Builtin(builtin::BuiltinValue::kFragDepth)}),
+        });
     Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
          utils::Vector{
              Return(Call(ty.Of(output))),
diff --git a/src/tint/resolver/expression_kind_test.cc b/src/tint/resolver/expression_kind_test.cc
index c8cea54..dc3d8a8 100644
--- a/src/tint/resolver/expression_kind_test.cc
+++ b/src/tint/resolver/expression_kind_test.cc
@@ -220,7 +220,7 @@
             GlobalVar("v", ty("texture_storage_2d", "rgba8unorm", expr), Group(0_u), Binding(0_u));
             break;
         case Use::kAddressSpace:
-            Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
+            Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
             Func("f", utils::Vector{Param("p", ty("ptr", expr, ty.f32()))}, ty.void_(),
                  utils::Empty);
             break;
diff --git a/src/tint/resolver/f16_extension_test.cc b/src/tint/resolver/f16_extension_test.cc
index f0d515f..d767919 100644
--- a/src/tint/resolver/f16_extension_test.cc
+++ b/src/tint/resolver/f16_extension_test.cc
@@ -27,7 +27,7 @@
 TEST_F(ResolverF16ExtensionTest, TypeUsedWithExtension) {
     // enable f16;
     // var<private> v : f16;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("v", ty.f16(), type::AddressSpace::kPrivate);
 
@@ -45,7 +45,7 @@
 TEST_F(ResolverF16ExtensionTest, Vec2TypeUsedWithExtension) {
     // enable f16;
     // var<private> v : vec2<f16>;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("v", ty.vec2<f16>(), type::AddressSpace::kPrivate);
 
@@ -63,7 +63,7 @@
 TEST_F(ResolverF16ExtensionTest, Vec2TypeInitUsedWithExtension) {
     // enable f16;
     // var<private> v = vec2<f16>();
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("v", vec2<f16>(), type::AddressSpace::kPrivate);
 
@@ -81,7 +81,7 @@
 TEST_F(ResolverF16ExtensionTest, Vec2TypeConvUsedWithExtension) {
     // enable f16;
     // var<private> v = vec2<f16>(vec2<f32>());
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("v", vec2<f16>(vec2<f32>()), type::AddressSpace::kPrivate);
 
@@ -99,7 +99,7 @@
 TEST_F(ResolverF16ExtensionTest, F16LiteralUsedWithExtension) {
     // enable f16;
     // var<private> v = 16h;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("v", Expr(16_h), type::AddressSpace::kPrivate);
 
@@ -119,7 +119,7 @@
 TEST_P(ResolverF16ExtensionBuiltinTypeAliasTest, Vec2hTypeUsedWithExtension) {
     // enable f16;
     // var<private> v : vec2h;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("v", ty(Source{{12, 34}}, GetParam()), type::AddressSpace::kPrivate);
 
diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc
index 511d379..7ef446a 100644
--- a/src/tint/resolver/function_validation_test.cc
+++ b/src/tint/resolver/function_validation_test.cc
@@ -188,7 +188,7 @@
              Return(Call(ty.vec4<f32>())),
          },
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
-         utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
+         utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -1081,7 +1081,7 @@
     auto& param = GetParam();
     auto ptr_type = ty("ptr", Ident(Source{{12, 34}}, param.address_space), ty.i32());
     auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
-    Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
+    Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     Func("f", utils::Vector{arg}, ty.void_(), utils::Empty);
 
     if (param.expectation == Expectation::kAlwaysPass ||
diff --git a/src/tint/resolver/host_shareable_validation_test.cc b/src/tint/resolver/host_shareable_validation_test.cc
index f699135..b518b57 100644
--- a/src/tint/resolver/host_shareable_validation_test.cc
+++ b/src/tint/resolver/host_shareable_validation_test.cc
@@ -97,7 +97,7 @@
 }
 
 TEST_F(ResolverHostShareableValidationTest, NoError) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* i1 = Structure("I1", utils::Vector{
                                    Member(Source{{1, 1}}, "w1", ty.f32()),
diff --git a/src/tint/resolver/materialize_test.cc b/src/tint/resolver/materialize_test.cc
index acd69a8..4824549 100644
--- a/src/tint/resolver/materialize_test.cc
+++ b/src/tint/resolver/materialize_test.cc
@@ -312,7 +312,7 @@
     MaterializeTest<std::tuple<Expectation, Method, Data>>;
 
 TEST_P(MaterializeAbstractNumericToConcreteType, Test) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     const auto& param = GetParam();
     const auto& expectation = std::get<0>(param);
@@ -1282,7 +1282,7 @@
 TEST_F(MaterializeAbstractStructure, Modf_Scalar_ExplicitType) {
     // var v = modf(1_h); // v is __modf_result_f16
     // v = modf(1);       // __modf_result_f16 <- __modf_result_abstract
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto* call = Call("modf", 1_a);
     WrapInFunction(Decl(Var("v", Call("modf", 1_h))),  //
                    Assign("v", call));
@@ -1301,7 +1301,7 @@
 TEST_F(MaterializeAbstractStructure, Modf_Vector_ExplicitType) {
     // var v = modf(vec2(1_h)); // v is __modf_result_vec2_f16
     // v = modf(vec2(1));       // __modf_result_vec2_f16 <- __modf_result_vec2_abstract
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto* call = Call("modf", Call(ty.vec2<Infer>(), 1_a));
     WrapInFunction(Decl(Var("v", Call("modf", Call(ty.vec2<Infer>(), 1_h)))), Assign("v", call));
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1363,7 +1363,7 @@
 TEST_F(MaterializeAbstractStructure, Frexp_Scalar_ExplicitType) {
     // var v = frexp(1_h); // v is __frexp_result_f16
     // v = frexp(1);       // __frexp_result_f16 <- __frexp_result_abstract
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto* call = Call("frexp", 1_a);
     WrapInFunction(Decl(Var("v", Call("frexp", 1_h))),  //
                    Assign("v", call));
@@ -1384,7 +1384,7 @@
 TEST_F(MaterializeAbstractStructure, Frexp_Vector_ExplicitType) {
     // var v = frexp(vec2(1_h)); // v is __frexp_result_vec2_f16
     // v = frexp(vec2(1));       // __frexp_result_vec2_f16 <- __frexp_result_vec2_abstract
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     auto* call = Call("frexp", Call(ty.vec2<Infer>(), 1_a));
     WrapInFunction(Decl(Var("v", Call("frexp", Call(ty.vec2<Infer>(), 1_h)))), Assign("v", call));
     ASSERT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/override_test.cc b/src/tint/resolver/override_test.cc
index 2fd48ed..a9518d2 100644
--- a/src/tint/resolver/override_test.cc
+++ b/src/tint/resolver/override_test.cc
@@ -103,7 +103,7 @@
 }
 
 TEST_F(ResolverOverrideTest, F16_TemporallyBan) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Override(Source{{12, 34}}, "a", ty.f16(), Expr(1_h), Id(1_u));
 
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 352c5e4..8c36ad7 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -143,7 +143,7 @@
 
     if (result) {
         // Run the uniformity analysis, which requires a complete semantic module.
-        if (!enabled_extensions_.Contains(ast::Extension::kChromiumDisableUniformityAnalysis)) {
+        if (!enabled_extensions_.Contains(builtin::Extension::kChromiumDisableUniformityAnalysis)) {
             if (!AnalyzeUniformity(builder_, dependencies_)) {
                 return false;
             }
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index c5223db..003fa3d 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -501,7 +501,7 @@
     DependencyGraph dependencies_;
     SemHelper sem_;
     Validator validator_;
-    ast::Extensions enabled_extensions_;
+    builtin::Extensions enabled_extensions_;
     utils::Vector<sem::Function*, 8> entry_points_;
     utils::Hashmap<const type::Type*, const Source*, 8> atomic_composite_info_;
     utils::Bitset<0> marked_;
diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc
index 3d32799..c0d48bc 100644
--- a/src/tint/resolver/resolver_test.cc
+++ b/src/tint/resolver/resolver_test.cc
@@ -873,7 +873,8 @@
 
 TEST_F(ResolverTest, Function_Parameters_Locations) {
     auto* param_a = Param("a", ty.f32(), utils::Vector{Location(3_a)});
-    auto* param_b = Param("b", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kVertexIndex)});
+    auto* param_b =
+        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);
@@ -891,7 +892,7 @@
                           Stage(ast::PipelineStage::kVertex),
                       },
                       utils::Vector{
-                          Builtin(ast::BuiltinValue::kPosition),
+                          Builtin(builtin::BuiltinValue::kPosition),
                       });
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -974,7 +975,7 @@
                           Stage(ast::PipelineStage::kVertex),
                       },
                       utils::Vector{
-                          Builtin(ast::BuiltinValue::kPosition),
+                          Builtin(builtin::BuiltinValue::kPosition),
                       });
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/side_effects_test.cc b/src/tint/resolver/side_effects_test.cc
index b4770e4..456b371 100644
--- a/src/tint/resolver/side_effects_test.cc
+++ b/src/tint/resolver/side_effects_test.cc
@@ -15,6 +15,7 @@
 #include "src/tint/resolver/resolver.h"
 
 #include "gtest/gtest.h"
+#include "src/tint/builtin/extension.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"
@@ -160,7 +161,7 @@
 using SideEffectsBuiltinTest = resolver::ResolverTestWithParam<Case>;
 
 TEST_P(SideEffectsBuiltinTest, Test) {
-    Enable(ast::Extension::kChromiumExperimentalDp4A);
+    Enable(tint::builtin::Extension::kChromiumExperimentalDp4A);
     auto& c = GetParam();
 
     uint32_t next_binding = 0;
diff --git a/src/tint/resolver/struct_layout_test.cc b/src/tint/resolver/struct_layout_test.cc
index 7288449..33f7599 100644
--- a/src/tint/resolver/struct_layout_test.cc
+++ b/src/tint/resolver/struct_layout_test.cc
@@ -55,7 +55,7 @@
 }
 
 TEST_F(ResolverStructLayoutTest, ScalarsWithF16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* s = Structure("S", utils::Vector{
                                  Member("a", ty.f32()),
@@ -134,7 +134,7 @@
 }
 
 TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* s = Structure("S", utils::Vector{
                                  Member("a", ty.array<i32, 3>()),
@@ -174,7 +174,7 @@
 }
 
 TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* s = Structure("S", utils::Vector{
                                  Member("a", ty.array<i32, 3>(utils::Vector{Stride(8)})),
@@ -335,7 +335,7 @@
 }
 
 TEST_F(ResolverStructLayoutTest, Matrix) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* s = Structure("S", utils::Vector{
                                  Member("a_1", ty.mat2x2<f32>()),
diff --git a/src/tint/resolver/struct_pipeline_stage_use_test.cc b/src/tint/resolver/struct_pipeline_stage_use_test.cc
index 1ffc907..90e9505 100644
--- a/src/tint/resolver/struct_pipeline_stage_use_test.cc
+++ b/src/tint/resolver/struct_pipeline_stage_use_test.cc
@@ -69,7 +69,7 @@
     Func("main", utils::Vector{Param("param", ty.Of(s))}, ty.vec4<f32>(),
          utils::Vector{Return(Call(ty.vec4<f32>()))},
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
-         utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
+         utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
@@ -80,9 +80,9 @@
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
-    auto* s =
-        Structure("S", utils::Vector{Member("a", ty.vec4<f32>(),
-                                            utils::Vector{Builtin(ast::BuiltinValue::kPosition)})});
+    auto* s = Structure(
+        "S", utils::Vector{Member("a", ty.vec4<f32>(),
+                                  utils::Vector{Builtin(builtin::BuiltinValue::kPosition)})});
 
     Func("main", utils::Empty, ty.Of(s), utils::Vector{Return(Call(ty.Of(s)))},
          utils::Vector{Stage(ast::PipelineStage::kVertex)});
@@ -125,8 +125,9 @@
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
     auto* s = Structure(
-        "S", utils::Vector{Member(
-                 "a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kLocalInvocationIndex)})});
+        "S",
+        utils::Vector{Member(
+            "a", ty.u32(), utils::Vector{Builtin(builtin::BuiltinValue::kLocalInvocationIndex)})});
 
     Func("main", utils::Vector{Param("param", ty.Of(s))}, ty.void_(), utils::Empty,
          utils::Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
@@ -140,9 +141,9 @@
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
-    auto* s =
-        Structure("S", utils::Vector{Member("a", ty.vec4<f32>(),
-                                            utils::Vector{Builtin(ast::BuiltinValue::kPosition)})});
+    auto* s = Structure(
+        "S", utils::Vector{Member("a", ty.vec4<f32>(),
+                                  utils::Vector{Builtin(builtin::BuiltinValue::kPosition)})});
 
     Func("vert_main", utils::Empty, ty.Of(s), utils::Vector{Return(Call(ty.Of(s)))},
          utils::Vector{Stage(ast::PipelineStage::kVertex)});
diff --git a/src/tint/resolver/type_initializer_validation_test.cc b/src/tint/resolver/type_initializer_validation_test.cc
index 0f7144b..dde1a2e 100644
--- a/src/tint/resolver/type_initializer_validation_test.cc
+++ b/src/tint/resolver/type_initializer_validation_test.cc
@@ -85,7 +85,7 @@
     // }
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* initializer_expr = params.create_rhs_ast_value(*this, 0);
 
@@ -186,7 +186,7 @@
     // }
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Func("foo", utils::Empty, params.create_rhs_ast_type(*this),
          utils::Vector{Return(Call(params.create_rhs_ast_type(*this)))}, {});
@@ -343,7 +343,7 @@
 TEST_P(ConversionInitializerValidTest, All) {
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     // var a : <lhs_type1> = <lhs_type2>(<rhs_type>(<rhs_value_expr>));
     auto lhs_type1 = params.lhs_type(*this);
@@ -449,7 +449,7 @@
        << FriendlyName(rhs_type) << "(<rhs value expr>))";
     SCOPED_TRACE(ss.str());
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* a = Var("a", lhs_type1, Call(lhs_type2, Call(rhs_type, rhs_value_expr)));
 
@@ -944,7 +944,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, F16_Success) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = Call<f16>(Expr(1.5_h));
     WrapInFunction(expr);
@@ -1000,7 +1000,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, Convert_u32_to_f16_Success) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = Call<f16>(123_u);
     WrapInFunction(expr);
@@ -1020,7 +1020,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, Convert_f16_to_f32_Success) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = Call<f32>(123_h);
     WrapInFunction(expr);
@@ -1052,7 +1052,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, Vec2F16_Error_ScalarArgumentTypeMismatch) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec2<f16>(Source{{12, 34}}, 1_h, 2_f));
 
@@ -1175,7 +1175,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, Vec2F16_Success_Scalar) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* tc = vec2<f16>(1_h, 1_h);
     WrapInFunction(tc);
@@ -1309,7 +1309,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, Vec3F16_Error_ScalarArgumentTypeMismatch) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(Source{{12, 34}}, 1_h, 2_h, 3_f));
 
@@ -1451,7 +1451,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, Vec3F16_Success_Scalar) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* tc = vec3<f16>(1_h, 1_h, 1_h);
     WrapInFunction(tc);
@@ -1632,7 +1632,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, Vec4F16_Error_ScalarArgumentTypeMismatch) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec4<f16>(Source{{12, 34}}, 1_h, 1_h, 1_f, 1_h));
 
@@ -1799,7 +1799,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, Vec4F16_Success_Scalar) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* tc = vec4<f16>(1_h, 1_h, 1_h, 1_h);
     WrapInFunction(tc);
@@ -2035,7 +2035,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec2ElementTypeFromScalars) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec2_bool = vec2<Infer>(true, false);
     auto* vec2_i32 = vec2<Infer>(1_i, 2_i);
@@ -2064,7 +2064,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec2ElementTypeFromVec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec2_bool = vec2<Infer>(vec2<bool>(true, false));
     auto* vec2_i32 = vec2<Infer>(vec2<i32>(1_i, 2_i));
@@ -2093,7 +2093,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec3ElementTypeFromScalars) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec3_bool = vec3<Infer>(Expr(true), Expr(false), Expr(true));
     auto* vec3_i32 = vec3<Infer>(Expr(1_i), Expr(2_i), Expr(3_i));
@@ -2122,7 +2122,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec3ElementTypeFromVec3) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec3_bool = vec3<Infer>(vec3<bool>(true, false, true));
     auto* vec3_i32 = vec3<Infer>(vec3<i32>(1_i, 2_i, 3_i));
@@ -2151,7 +2151,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec3ElementTypeFromScalarAndVec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec3_bool = vec3<Infer>(Expr(true), vec2<bool>(false, true));
     auto* vec3_i32 = vec3<Infer>(Expr(1_i), vec2<i32>(2_i, 3_i));
@@ -2180,7 +2180,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec4ElementTypeFromScalars) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec4_bool = vec4<Infer>(Expr(true), Expr(false), Expr(true), Expr(false));
     auto* vec4_i32 = vec4<Infer>(Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i));
@@ -2209,7 +2209,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec4ElementTypeFromVec4) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec4_bool = vec4<Infer>(vec4<bool>(true, false, true, false));
     auto* vec4_i32 = vec4<Infer>(vec4<i32>(1_i, 2_i, 3_i, 4_i));
@@ -2238,7 +2238,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec4ElementTypeFromScalarAndVec3) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec4_bool = vec4<Infer>(Expr(true), vec3<bool>(false, true, false));
     auto* vec4_i32 = vec4<Infer>(Expr(1_i), vec3<i32>(2_i, 3_i, 4_i));
@@ -2267,7 +2267,7 @@
 }
 
 TEST_F(ResolverTypeInitializerValidationTest, InferVec4ElementTypeFromVec2AndVec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec4_bool = vec4<Infer>(vec2<bool>(true, false), vec2<bool>(true, false));
     auto* vec4_i32 = vec4<Infer>(vec2<i32>(1_i, 2_i), vec2<i32>(3_i, 4_i));
@@ -2406,7 +2406,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     const std::string element_type_name = param.get_element_type_name();
     std::stringstream args_tys;
@@ -2435,7 +2435,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     const std::string element_type_name = param.get_element_type_name();
     std::stringstream args_tys;
@@ -2463,7 +2463,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     const std::string element_type_name = param.get_element_type_name();
     std::stringstream args_tys;
@@ -2492,7 +2492,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     const std::string element_type_name = param.get_element_type_name();
     std::stringstream args_tys;
@@ -2520,7 +2520,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     std::stringstream args_tys;
     utils::Vector<const ast::Expression*, 8> args;
@@ -2548,7 +2548,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     std::stringstream args_tys;
     utils::Vector<const ast::Expression*, 8> args;
@@ -2580,7 +2580,7 @@
         return;
     }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     const std::string element_type_name = param.get_element_type_name();
     std::stringstream args_tys;
@@ -2618,7 +2618,7 @@
         return;
     }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     const std::string element_type_name = param.get_element_type_name();
     std::stringstream args_tys;
@@ -2650,7 +2650,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     ast::Type matrix_type = param.create_mat_ast_type(*this);
     auto* tc = Call(Source{{12, 40}}, matrix_type);
@@ -2665,7 +2665,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     utils::Vector<const ast::Expression*, 4> args;
     for (uint32_t i = 0; i < param.columns; i++) {
@@ -2686,7 +2686,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     utils::Vector<const ast::Expression*, 16> args;
     for (uint32_t i = 0; i < param.columns * param.rows; i++) {
@@ -2706,7 +2706,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this));
 
@@ -2736,7 +2736,7 @@
 
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this));
 
@@ -2767,7 +2767,7 @@
 TEST_P(MatrixInitializerTest, ArgumentTypeAlias_Success) {
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     ast::Type matrix_type = param.create_mat_ast_type(*this);
     ast::Type vec_type = param.create_column_ast_type(*this);
@@ -2787,7 +2787,7 @@
 TEST_P(MatrixInitializerTest, ArgumentElementTypeAlias_Error) {
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     ast::Type matrix_type = param.create_mat_ast_type(*this);
     auto* u32_type_alias = Alias("UnsignedInt", ty.u32());
@@ -2814,7 +2814,7 @@
 TEST_P(MatrixInitializerTest, ArgumentElementTypeAlias_Success) {
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this));
 
@@ -2834,7 +2834,7 @@
 TEST_P(MatrixInitializerTest, InferElementTypeFromVectors) {
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     utils::Vector<const ast::Expression*, 8> args;
     for (uint32_t i = 0; i < param.columns; i++) {
@@ -2851,7 +2851,7 @@
 TEST_P(MatrixInitializerTest, InferElementTypeFromScalars) {
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     utils::Vector<const ast::Expression*, 8> args;
     for (uint32_t i = 0; i < param.rows * param.columns; i++) {
@@ -2867,7 +2867,7 @@
 TEST_P(MatrixInitializerTest, CannotInferElementTypeFromVectors_Mismatch) {
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     std::stringstream err;
     err << "12:34 error: no matching initializer for mat" << param.columns << "x" << param.rows
@@ -2898,7 +2898,7 @@
 TEST_P(MatrixInitializerTest, CannotInferElementTypeFromScalars_Mismatch) {
     const auto param = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     std::stringstream err;
     err << "12:34 error: no matching initializer for mat" << param.columns << "x" << param.rows
@@ -2988,7 +2988,7 @@
     auto& str_params = std::get<0>(param);
     uint32_t N = std::get<1>(param);
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     utils::Vector<const ast::StructMember*, 16> members;
     utils::Vector<const ast::Expression*, 16> values;
@@ -3013,7 +3013,7 @@
     auto& str_params = std::get<0>(param);
     uint32_t N = std::get<1>(param);
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     utils::Vector<const ast::StructMember*, 16> members;
     utils::Vector<const ast::Expression*, 8> values;
@@ -3046,7 +3046,7 @@
     auto& ctor_params = std::get<1>(param);
     uint32_t N = std::get<2>(param);
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     if (str_params.ast == ctor_params.ast) {
         return;
diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc
index 0e69da8..efc55f0 100644
--- a/src/tint/resolver/type_validation_test.cc
+++ b/src/tint/resolver/type_validation_test.cc
@@ -1005,7 +1005,7 @@
 using SampledTextureTypeTest = ResolverTestWithParam<TypeParams>;
 TEST_P(SampledTextureTypeTest, All) {
     auto& params = GetParam();
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     GlobalVar(
         "a",
         ty.sampled_texture(Source{{12, 34}}, type::TextureDimension::k2d, params.type_func(*this)),
@@ -1025,7 +1025,7 @@
 using MultisampledTextureTypeTest = ResolverTestWithParam<TypeParams>;
 TEST_P(MultisampledTextureTypeTest, All) {
     auto& params = GetParam();
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     GlobalVar("a",
               ty.multisampled_texture(Source{{12, 34}}, type::TextureDimension::k2d,
                                       params.type_func(*this)),
@@ -1231,7 +1231,7 @@
     // var a : matNxM<EL_TY>;
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     ast::Type el_ty = params.elem_ty(*this);
 
@@ -1271,7 +1271,7 @@
     // var a : matNxM<EL_TY>;
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     ast::Type el_ty = params.elem_ty(*this);
 
@@ -1316,7 +1316,7 @@
     // var a : vecN<EL_TY>;
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.vec(params.elem_ty(*this), params.width), type::AddressSpace::kPrivate);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1350,7 +1350,7 @@
     // var a : vecN<EL_TY>;
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
               type::AddressSpace::kPrivate);
@@ -1389,7 +1389,7 @@
     // explicit = aliased;
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Var("aliased", ty(params.alias))),
                    Decl(Var("explicit", params.type(*this))),  //
@@ -1401,7 +1401,7 @@
     // var v : vecN<T> = vecTN();
     auto& params = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Var("v", params.type(*this), Call(params.alias))));
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1449,7 +1449,7 @@
     // enable f16;
     // var<private> v : f32<true>;
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, GetParam(), true));
 
     EXPECT_FALSE(r()->Resolve());
@@ -1462,7 +1462,7 @@
     // alias A = f32;
     // var<private> v : A<true>;
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
     Alias(Source{{56, 78}}, "A", ty(GetParam()));
     GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, "A", true));
 
diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc
index 0b8fd7f..61e0dad 100644
--- a/src/tint/resolver/uniformity.cc
+++ b/src/tint/resolver/uniformity.cc
@@ -1148,8 +1148,8 @@
         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 == ast::BuiltinValue::kNumWorkgroups ||
-                    builtin->builtin == ast::BuiltinValue::kWorkgroupId) {
+                if (builtin->builtin == builtin::BuiltinValue::kNumWorkgroups ||
+                    builtin->builtin == builtin::BuiltinValue::kWorkgroupId) {
                     return false;
                 }
             }
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index 1cf996d..fbd0912 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -7390,7 +7390,7 @@
     EXPECT_EQ(error_,
               R"(test:5:41 error: 'dpdx' must only be called from uniform control flow
   let b = (non_uniform_global == 0) && (dpdx(1.0) == 0.0);
-                                        ^^^^
+                                        ^^^^^^^^^
 
 test:5:37 note: control flow depends on possibly non-uniform value
   let b = (non_uniform_global == 0) && (dpdx(1.0) == 0.0);
@@ -7784,7 +7784,7 @@
 
 test:5:7 note: return value of 'atomicAdd' may be non-uniform
   if (atomicAdd(&a, 1) == 1) {
-      ^^^^^^^^^
+      ^^^^^^^^^^^^^^^^
 )");
 }
 
@@ -7811,7 +7811,7 @@
 
 test:5:7 note: return value of 'atomicAdd' may be non-uniform
   if (atomicAdd(&a, 1) == 1) {
-      ^^^^^^^^^
+      ^^^^^^^^^^^^^^^^
 )");
 }
 
@@ -8154,7 +8154,7 @@
     EXPECT_EQ(error_,
               R"(test:10:9 error: 'dpdy' must only be called from uniform control flow
     _ = dpdy(1.0); // Should trigger an error
-        ^^^^
+        ^^^^^^^^^
 
 test:9:3 note: control flow depends on possibly non-uniform value
   if (x < 0.5) {
@@ -8162,7 +8162,7 @@
 
 test:6:9 note: return value of 'dpdx' may be non-uniform
     x = dpdx(1.0);
-        ^^^^
+        ^^^^^^^^^
 )");
 }
 
@@ -8194,7 +8194,7 @@
     EXPECT_EQ(error_,
               R"(test:16:9 error: 'dpdy' must only be called from uniform control flow
     _ = dpdy(1.0); // Should trigger an error
-        ^^^^
+        ^^^^^^^^^
 
 test:15:3 note: control flow depends on possibly non-uniform value
   if (ret) {
@@ -8423,7 +8423,7 @@
 
 test:17:7 note: return value of 'foo' may be non-uniform
   if (foo() == 42) {
-      ^^^
+      ^^^^^
 )");
 }
 
diff --git a/src/tint/resolver/validation_test.cc b/src/tint/resolver/validation_test.cc
index 634e3a2..73fa9b8 100644
--- a/src/tint/resolver/validation_test.cc
+++ b/src/tint/resolver/validation_test.cc
@@ -75,7 +75,7 @@
              Stage(ast::PipelineStage::kVertex),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kPosition),
+             Builtin(builtin::BuiltinValue::kPosition),
          });
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index 0a7abcf..44d6c5b 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -149,7 +149,7 @@
 Validator::Validator(
     ProgramBuilder* builder,
     SemHelper& sem,
-    const ast::Extensions& enabled_extensions,
+    const builtin::Extensions& enabled_extensions,
     const utils::Hashmap<const type::Type*, const Source*, 8>& atomic_composite_info,
     utils::Hashset<TypeAndAddressSpace, 8>& valid_type_storage_layouts)
     : symbols_(builder->Symbols()),
@@ -829,7 +829,7 @@
                 case type::AddressSpace::kUniform:
                 case type::AddressSpace::kWorkgroup:
                     ok = enabled_extensions_.Contains(
-                        ast::Extension::kChromiumExperimentalFullPtrParameters);
+                        builtin::Extension::kChromiumExperimentalFullPtrParameters);
                     break;
                 default:
                     break;
@@ -868,7 +868,7 @@
     bool is_stage_mismatch = false;
     bool is_output = !is_input;
     switch (attr->builtin) {
-        case ast::BuiltinValue::kPosition:
+        case builtin::BuiltinValue::kPosition:
             if (stage != ast::PipelineStage::kNone &&
                 !((is_input && stage == ast::PipelineStage::kFragment) ||
                   (is_output && stage == ast::PipelineStage::kVertex))) {
@@ -880,10 +880,10 @@
                 return false;
             }
             break;
-        case ast::BuiltinValue::kGlobalInvocationId:
-        case ast::BuiltinValue::kLocalInvocationId:
-        case ast::BuiltinValue::kNumWorkgroups:
-        case ast::BuiltinValue::kWorkgroupId:
+        case builtin::BuiltinValue::kGlobalInvocationId:
+        case builtin::BuiltinValue::kLocalInvocationId:
+        case builtin::BuiltinValue::kNumWorkgroups:
+        case builtin::BuiltinValue::kWorkgroupId:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kCompute && is_input)) {
                 is_stage_mismatch = true;
@@ -894,7 +894,7 @@
                 return false;
             }
             break;
-        case ast::BuiltinValue::kFragDepth:
+        case builtin::BuiltinValue::kFragDepth:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kFragment && !is_input)) {
                 is_stage_mismatch = true;
@@ -904,7 +904,7 @@
                 return false;
             }
             break;
-        case ast::BuiltinValue::kFrontFacing:
+        case builtin::BuiltinValue::kFrontFacing:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kFragment && is_input)) {
                 is_stage_mismatch = true;
@@ -914,7 +914,7 @@
                 return false;
             }
             break;
-        case ast::BuiltinValue::kLocalInvocationIndex:
+        case builtin::BuiltinValue::kLocalInvocationIndex:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kCompute && is_input)) {
                 is_stage_mismatch = true;
@@ -924,8 +924,8 @@
                 return false;
             }
             break;
-        case ast::BuiltinValue::kVertexIndex:
-        case ast::BuiltinValue::kInstanceIndex:
+        case builtin::BuiltinValue::kVertexIndex:
+        case builtin::BuiltinValue::kInstanceIndex:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kVertex && is_input)) {
                 is_stage_mismatch = true;
@@ -935,7 +935,7 @@
                 return false;
             }
             break;
-        case ast::BuiltinValue::kSampleMask:
+        case builtin::BuiltinValue::kSampleMask:
             if (stage != ast::PipelineStage::kNone && !(stage == ast::PipelineStage::kFragment)) {
                 is_stage_mismatch = true;
             }
@@ -944,7 +944,7 @@
                 return false;
             }
             break;
-        case ast::BuiltinValue::kSampleIndex:
+        case builtin::BuiltinValue::kSampleIndex:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kFragment && is_input)) {
                 is_stage_mismatch = true;
@@ -1076,7 +1076,7 @@
     // order to catch conflicts.
     // TODO(jrprice): This state could be stored in sem::Function instead, and then passed to
     // sem::Function since it would be useful there too.
-    utils::Hashset<ast::BuiltinValue, 4> builtins;
+    utils::Hashset<builtin::BuiltinValue, 4> builtins;
     utils::Hashset<uint32_t, 8> locations;
     enum class ParamOrRetType {
         kParameter,
@@ -1211,7 +1211,7 @@
                 bool has_position = false;
                 if (pipeline_io_attribute) {
                     if (auto* builtin = pipeline_io_attribute->As<ast::BuiltinAttribute>()) {
-                        has_position = (builtin->builtin == ast::BuiltinValue::kPosition);
+                        has_position = (builtin->builtin == builtin::BuiltinValue::kPosition);
                     }
                 }
                 if (!has_position) {
@@ -1275,13 +1275,13 @@
     }
 
     if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
-        !builtins.Contains(ast::BuiltinValue::kPosition)) {
+        !builtins.Contains(builtin::BuiltinValue::kPosition)) {
         // Check module-scope variables, as the SPIR-V sanitizer generates these.
         bool found = false;
         for (auto* global : func->TransitivelyReferencedGlobals()) {
             if (auto* builtin =
                     ast::GetAttribute<ast::BuiltinAttribute>(global->Declaration()->attributes)) {
-                if (builtin->builtin == ast::BuiltinValue::kPosition) {
+                if (builtin->builtin == builtin::BuiltinValue::kPosition) {
                     found = true;
                     break;
                 }
@@ -1653,7 +1653,7 @@
     }
 
     const auto extension = builtin->RequiredExtension();
-    if (extension == ast::Extension::kUndefined) {
+    if (extension == builtin::Extension::kUndefined) {
         return true;
     }
 
@@ -1669,7 +1669,7 @@
 
 bool Validator::CheckF16Enabled(const Source& source) const {
     // Validate if f16 type is allowed.
-    if (!enabled_extensions_.Contains(ast::Extension::kF16)) {
+    if (!enabled_extensions_.Contains(builtin::Extension::kF16)) {
         AddError("f16 type used without 'f16' extension enabled", source);
         return false;
     }
@@ -1719,7 +1719,8 @@
         }
 
         if (param_type->Is<type::Pointer>() &&
-            !enabled_extensions_.Contains(ast::Extension::kChromiumExperimentalFullPtrParameters)) {
+            !enabled_extensions_.Contains(
+                builtin::Extension::kChromiumExperimentalFullPtrParameters)) {
             // https://gpuweb.github.io/gpuweb/wgsl/#function-restriction
             // Each argument of pointer type to a user-defined function must have the same memory
             // view as its root identifier.
@@ -2123,7 +2124,7 @@
                                           /* is_input */ false)) {
                         return false;
                     }
-                    if (builtin->builtin == ast::BuiltinValue::kPosition) {
+                    if (builtin->builtin == builtin::BuiltinValue::kPosition) {
                         has_position = true;
                     }
                     return true;
@@ -2512,7 +2513,7 @@
     }
 
     if (address_space == type::AddressSpace::kPushConstant &&
-        !enabled_extensions_.Contains(ast::Extension::kChromiumExperimentalPushConstant) &&
+        !enabled_extensions_.Contains(builtin::Extension::kChromiumExperimentalPushConstant) &&
         IsValidationEnabled(attributes, ast::DisabledValidation::kIgnoreAddressSpace)) {
         AddError(
             "use of variable address space 'push_constant' requires enabling extension "
diff --git a/src/tint/resolver/validator.h b/src/tint/resolver/validator.h
index dc1bea6..499dcda 100644
--- a/src/tint/resolver/validator.h
+++ b/src/tint/resolver/validator.h
@@ -102,7 +102,7 @@
     /// @param valid_type_storage_layouts a set of validated type layouts by address space
     Validator(ProgramBuilder* builder,
               SemHelper& helper,
-              const ast::Extensions& enabled_extensions,
+              const builtin::Extensions& enabled_extensions,
               const utils::Hashmap<const type::Type*, const Source*, 8>& atomic_composite_info,
               utils::Hashset<TypeAndAddressSpace, 8>& valid_type_storage_layouts);
     ~Validator();
@@ -550,7 +550,7 @@
     diag::List& diagnostics_;
     SemHelper& sem_;
     DiagnosticFilterStack diagnostic_filters_;
-    const ast::Extensions& enabled_extensions_;
+    const builtin::Extensions& enabled_extensions_;
     const utils::Hashmap<const type::Type*, const Source*, 8>& atomic_composite_info_;
     utils::Hashset<TypeAndAddressSpace, 8>& valid_type_storage_layouts_;
 };
diff --git a/src/tint/resolver/variable_test.cc b/src/tint/resolver/variable_test.cc
index c5af49c..2239945 100644
--- a/src/tint/resolver/variable_test.cc
+++ b/src/tint/resolver/variable_test.cc
@@ -41,7 +41,7 @@
     //   var a : A;
     // }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* S = Structure("S", utils::Vector{Member("i", ty.i32())});
     auto* A = Alias("A", ty.Of(S));
@@ -106,7 +106,7 @@
     //   var a : A = A(1);
     // }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* S = Structure("S", utils::Vector{Member("i", ty.i32())});
     auto* A = Alias("A", ty.Of(S));
@@ -399,7 +399,7 @@
     //   let p : pointer<function, i32> = &v;
     // }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* S = Structure("S", utils::Vector{Member("i", ty.i32())});
     auto* A = Alias("A", ty.Of(S));
diff --git a/src/tint/resolver/variable_validation_test.cc b/src/tint/resolver/variable_validation_test.cc
index 2649562..738d926 100644
--- a/src/tint/resolver/variable_validation_test.cc
+++ b/src/tint/resolver/variable_validation_test.cc
@@ -488,7 +488,7 @@
 TEST_F(ResolverVariableValidationTest, GlobalVariable_PushConstantWithInitializer) {
     // enable chromium_experimental_push_constant;
     // var<push_constant> a : u32 = 0u;
-    Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     GlobalVar(Source{{1u, 2u}}, "a", ty.u32(), type::AddressSpace::kPushConstant,
               Expr(Source{{3u, 4u}}, u32(0)));
 
diff --git a/src/tint/sem/builtin.cc b/src/tint/sem/builtin.cc
index 243e1b7..7d13190 100644
--- a/src/tint/sem/builtin.cc
+++ b/src/tint/sem/builtin.cc
@@ -179,11 +179,11 @@
     return false;
 }
 
-ast::Extension Builtin::RequiredExtension() const {
+builtin::Extension Builtin::RequiredExtension() const {
     if (IsDP4a()) {
-        return ast::Extension::kChromiumExperimentalDp4A;
+        return builtin::Extension::kChromiumExperimentalDp4A;
     }
-    return ast::Extension::kUndefined;
+    return builtin::Extension::kUndefined;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/builtin.h b/src/tint/sem/builtin.h
index a733131..71e5467 100644
--- a/src/tint/sem/builtin.h
+++ b/src/tint/sem/builtin.h
@@ -18,7 +18,7 @@
 #include <string>
 #include <vector>
 
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
 #include "src/tint/sem/builtin_type.h"
 #include "src/tint/sem/call_target.h"
 #include "src/tint/sem/pipeline_stage_set.h"
@@ -147,8 +147,8 @@
     bool HasSideEffects() const;
 
     /// @returns the required extension of this builtin function. Returns
-    /// ast::Extension::kNone if no extension is required.
-    ast::Extension RequiredExtension() const;
+    /// builtin::Extension::kNone if no extension is required.
+    builtin::Extension RequiredExtension() const;
 
   private:
     const BuiltinType type_;
diff --git a/src/tint/sem/module.cc b/src/tint/sem/module.cc
index 38f0ec6..971c7f2 100644
--- a/src/tint/sem/module.cc
+++ b/src/tint/sem/module.cc
@@ -21,7 +21,7 @@
 
 namespace tint::sem {
 
-Module::Module(utils::VectorRef<const ast::Node*> dep_ordered_decls, ast::Extensions extensions)
+Module::Module(utils::VectorRef<const ast::Node*> dep_ordered_decls, builtin::Extensions extensions)
     : dep_ordered_decls_(std::move(dep_ordered_decls)), extensions_(std::move(extensions)) {}
 
 Module::~Module() = default;
diff --git a/src/tint/sem/module.h b/src/tint/sem/module.h
index 21b08f2..6bcd802 100644
--- a/src/tint/sem/module.h
+++ b/src/tint/sem/module.h
@@ -16,7 +16,7 @@
 #define SRC_TINT_SEM_MODULE_H_
 
 #include "src/tint/ast/diagnostic_control.h"
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
 #include "src/tint/sem/node.h"
 #include "src/tint/utils/vector.h"
 
@@ -34,7 +34,7 @@
     /// Constructor
     /// @param dep_ordered_decls the dependency-ordered module-scope declarations
     /// @param extensions the list of enabled extensions in the module
-    Module(utils::VectorRef<const ast::Node*> dep_ordered_decls, ast::Extensions extensions);
+    Module(utils::VectorRef<const ast::Node*> dep_ordered_decls, builtin::Extensions extensions);
 
     /// Destructor
     ~Module() override;
@@ -45,7 +45,7 @@
     }
 
     /// @returns the list of enabled extensions in the module
-    const ast::Extensions& Extensions() const { return extensions_; }
+    const builtin::Extensions& Extensions() const { return extensions_; }
 
     /// Modifies the severity of a specific diagnostic rule for this module.
     /// @param rule the diagnostic rule
@@ -61,7 +61,7 @@
 
   private:
     const utils::Vector<const ast::Node*, 64> dep_ordered_decls_;
-    ast::Extensions extensions_;
+    builtin::Extensions extensions_;
     ast::DiagnosticRuleSeverities diagnostic_severities_;
 };
 
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc
index e140fb3..917d418 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/transform/builtin_polyfill.cc
@@ -45,7 +45,7 @@
     State(CloneContext& c, Builtins p) : ctx(c), polyfill(p) {
         has_full_ptr_params = false;
         for (auto* enable : c.src->AST().Enables()) {
-            if (enable->extension == ast::Extension::kChromiumExperimentalFullPtrParameters) {
+            if (enable->extension == builtin::Extension::kChromiumExperimentalFullPtrParameters) {
                 has_full_ptr_params = true;
             }
         }
@@ -673,7 +673,7 @@
     /// @return the polyfill function name
     Symbol workgroupUniformLoad(const type::Type* type) {
         if (!has_full_ptr_params) {
-            b.Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
+            b.Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
             has_full_ptr_params = true;
         }
         auto name = b.Symbols().New("tint_workgroupUniformLoad");
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/transform/canonicalize_entry_point_io.cc
index 81c2821..049e9ca 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/transform/canonicalize_entry_point_io.cc
@@ -47,33 +47,33 @@
 
 /// FXC is sensitive to field order in structures, this is used by StructMemberComparator to ensure
 /// that FXC is happy with the order of emitted fields.
-uint32_t BuiltinOrder(ast::BuiltinValue builtin) {
+uint32_t BuiltinOrder(builtin::BuiltinValue builtin) {
     switch (builtin) {
-        case ast::BuiltinValue::kPosition:
+        case builtin::BuiltinValue::kPosition:
             return 1;
-        case ast::BuiltinValue::kVertexIndex:
+        case builtin::BuiltinValue::kVertexIndex:
             return 2;
-        case ast::BuiltinValue::kInstanceIndex:
+        case builtin::BuiltinValue::kInstanceIndex:
             return 3;
-        case ast::BuiltinValue::kFrontFacing:
+        case builtin::BuiltinValue::kFrontFacing:
             return 4;
-        case ast::BuiltinValue::kFragDepth:
+        case builtin::BuiltinValue::kFragDepth:
             return 5;
-        case ast::BuiltinValue::kLocalInvocationId:
+        case builtin::BuiltinValue::kLocalInvocationId:
             return 6;
-        case ast::BuiltinValue::kLocalInvocationIndex:
+        case builtin::BuiltinValue::kLocalInvocationIndex:
             return 7;
-        case ast::BuiltinValue::kGlobalInvocationId:
+        case builtin::BuiltinValue::kGlobalInvocationId:
             return 8;
-        case ast::BuiltinValue::kWorkgroupId:
+        case builtin::BuiltinValue::kWorkgroupId:
             return 9;
-        case ast::BuiltinValue::kNumWorkgroups:
+        case builtin::BuiltinValue::kNumWorkgroups:
             return 10;
-        case ast::BuiltinValue::kSampleIndex:
+        case builtin::BuiltinValue::kSampleIndex:
             return 11;
-        case ast::BuiltinValue::kSampleMask:
+        case builtin::BuiltinValue::kSampleMask:
             return 12;
-        case ast::BuiltinValue::kPointSize:
+        case builtin::BuiltinValue::kPointSize:
             return 13;
         default:
             break;
@@ -118,7 +118,7 @@
 // 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 == ast::BuiltinValue::kSampleMask;
+    return builtin && builtin->builtin == builtin::BuiltinValue::kSampleMask;
 }
 
 }  // namespace
@@ -244,7 +244,7 @@
             if (builtin) {
                 if (cfg.shader_style == ShaderStyle::kGlsl) {
                     value = FromGLSLBuiltin(builtin->builtin, value, ast_type);
-                } else if (builtin->builtin == ast::BuiltinValue::kSampleMask) {
+                } else if (builtin->builtin == 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);
@@ -422,7 +422,7 @@
         // 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(ast::BuiltinValue::kSampleMask)},
+                  {ctx.dst->Builtin(builtin::BuiltinValue::kSampleMask)},
                   ctx.dst->Expr(u32(cfg.fixed_sample_mask)));
     }
 
@@ -430,7 +430,7 @@
     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(ast::BuiltinValue::kPointSize)}, ctx.dst->Expr(1_f));
+                  {ctx.dst->Builtin(builtin::BuiltinValue::kPointSize)}, ctx.dst->Expr(1_f));
     }
 
     /// Create an expression for gl_Position.[component]
@@ -675,11 +675,11 @@
     /// @param stage the current pipeline stage
     /// @param address_space the address space (input or output)
     /// @returns the gl_ string corresponding to that builtin
-    const char* GLSLBuiltinToString(ast::BuiltinValue builtin,
+    const char* GLSLBuiltinToString(builtin::BuiltinValue builtin,
                                     ast::PipelineStage stage,
                                     type::AddressSpace address_space) {
         switch (builtin) {
-            case ast::BuiltinValue::kPosition:
+            case builtin::BuiltinValue::kPosition:
                 switch (stage) {
                     case ast::PipelineStage::kVertex:
                         return "gl_Position";
@@ -688,27 +688,27 @@
                     default:
                         return "";
                 }
-            case ast::BuiltinValue::kVertexIndex:
+            case builtin::BuiltinValue::kVertexIndex:
                 return "gl_VertexID";
-            case ast::BuiltinValue::kInstanceIndex:
+            case builtin::BuiltinValue::kInstanceIndex:
                 return "gl_InstanceID";
-            case ast::BuiltinValue::kFrontFacing:
+            case builtin::BuiltinValue::kFrontFacing:
                 return "gl_FrontFacing";
-            case ast::BuiltinValue::kFragDepth:
+            case builtin::BuiltinValue::kFragDepth:
                 return "gl_FragDepth";
-            case ast::BuiltinValue::kLocalInvocationId:
+            case builtin::BuiltinValue::kLocalInvocationId:
                 return "gl_LocalInvocationID";
-            case ast::BuiltinValue::kLocalInvocationIndex:
+            case builtin::BuiltinValue::kLocalInvocationIndex:
                 return "gl_LocalInvocationIndex";
-            case ast::BuiltinValue::kGlobalInvocationId:
+            case builtin::BuiltinValue::kGlobalInvocationId:
                 return "gl_GlobalInvocationID";
-            case ast::BuiltinValue::kNumWorkgroups:
+            case builtin::BuiltinValue::kNumWorkgroups:
                 return "gl_NumWorkGroups";
-            case ast::BuiltinValue::kWorkgroupId:
+            case builtin::BuiltinValue::kWorkgroupId:
                 return "gl_WorkGroupID";
-            case ast::BuiltinValue::kSampleIndex:
+            case builtin::BuiltinValue::kSampleIndex:
                 return "gl_SampleID";
-            case ast::BuiltinValue::kSampleMask:
+            case builtin::BuiltinValue::kSampleMask:
                 if (address_space == type::AddressSpace::kIn) {
                     return "gl_SampleMaskIn";
                 } else {
@@ -725,18 +725,18 @@
     /// @param ast_type (inout) the incoming WGSL and outgoing GLSL types
     /// @returns an expression representing the GLSL builtin converted to what
     /// WGSL expects
-    const ast::Expression* FromGLSLBuiltin(ast::BuiltinValue builtin,
+    const ast::Expression* FromGLSLBuiltin(builtin::BuiltinValue builtin,
                                            const ast::Expression* value,
                                            ast::Type& ast_type) {
         switch (builtin) {
-            case ast::BuiltinValue::kVertexIndex:
-            case ast::BuiltinValue::kInstanceIndex:
-            case ast::BuiltinValue::kSampleIndex:
+            case builtin::BuiltinValue::kVertexIndex:
+            case builtin::BuiltinValue::kInstanceIndex:
+            case builtin::BuiltinValue::kSampleIndex:
                 // GLSL uses i32 for these, so bitcast to u32.
                 value = ctx.dst->Bitcast(ast_type, value);
                 ast_type = ctx.dst->ty.i32();
                 break;
-            case ast::BuiltinValue::kSampleMask:
+            case builtin::BuiltinValue::kSampleMask:
                 // gl_SampleMask is an array of i32. Retrieve the first element and
                 // bitcast it to u32.
                 value = ctx.dst->IndexAccessor(value, 0_i);
@@ -755,14 +755,14 @@
     /// @param value the value to convert
     /// @param type (out) the type to which the value was converted
     /// @returns the converted value which can be assigned to the GLSL builtin
-    const ast::Expression* ToGLSLBuiltin(ast::BuiltinValue builtin,
+    const ast::Expression* ToGLSLBuiltin(builtin::BuiltinValue builtin,
                                          const ast::Expression* value,
                                          const type::Type*& type) {
         switch (builtin) {
-            case ast::BuiltinValue::kVertexIndex:
-            case ast::BuiltinValue::kInstanceIndex:
-            case ast::BuiltinValue::kSampleIndex:
-            case ast::BuiltinValue::kSampleMask:
+            case builtin::BuiltinValue::kVertexIndex:
+            case builtin::BuiltinValue::kInstanceIndex:
+            case builtin::BuiltinValue::kSampleIndex:
+            case builtin::BuiltinValue::kSampleMask:
                 type = ctx.dst->create<type::I32>();
                 value = ctx.dst->Bitcast(CreateASTTypeFor(ctx, type), value);
                 break;
diff --git a/src/tint/transform/clamp_frag_depth.cc b/src/tint/transform/clamp_frag_depth.cc
index 0b8d8f7..57d9a40 100644
--- a/src/tint/transform/clamp_frag_depth.cc
+++ b/src/tint/transform/clamp_frag_depth.cc
@@ -18,10 +18,10 @@
 
 #include "src/tint/ast/attribute.h"
 #include "src/tint/ast/builtin_attribute.h"
-#include "src/tint/ast/builtin_value.h"
 #include "src/tint/ast/function.h"
 #include "src/tint/ast/module.h"
 #include "src/tint/ast/struct.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/statement.h"
@@ -38,7 +38,7 @@
 bool ContainsFragDepth(utils::VectorRef<const ast::Attribute*> attributes) {
     for (auto* attribute : attributes) {
         if (auto* builtin_attribute = attribute->As<ast::BuiltinAttribute>()) {
-            if (builtin_attribute->builtin == ast::BuiltinValue::kFragDepth) {
+            if (builtin_attribute->builtin == builtin::BuiltinValue::kFragDepth) {
                 return true;
             }
         }
@@ -117,7 +117,7 @@
     //   fn clamp_frag_depth(v : f32) -> f32 {
     //       return clamp(v, frag_depth_clamp_args.min, frag_depth_clamp_args.max);
     //   }
-    b.Enable(ast::Extension::kChromiumExperimentalPushConstant);
+    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())});
diff --git a/src/tint/transform/direct_variable_access.cc b/src/tint/transform/direct_variable_access.cc
index a8a1272..8ae3e22 100644
--- a/src/tint/transform/direct_variable_access.cc
+++ b/src/tint/transform/direct_variable_access.cc
@@ -203,7 +203,7 @@
     /// @returns the ApplyResult
     ApplyResult Run() {
         if (!ctx.src->Sem().Module()->Extensions().Contains(
-                ast::Extension::kChromiumExperimentalFullPtrParameters)) {
+                builtin::Extension::kChromiumExperimentalFullPtrParameters)) {
             // If the 'chromium_experimental_full_ptr_parameters' extension is not enabled, then
             // there's nothing for this transform to do.
             return SkipTransform;
diff --git a/src/tint/transform/disable_uniformity_analysis.cc b/src/tint/transform/disable_uniformity_analysis.cc
index ffd0b18..7c26fb8 100644
--- a/src/tint/transform/disable_uniformity_analysis.cc
+++ b/src/tint/transform/disable_uniformity_analysis.cc
@@ -31,13 +31,13 @@
                                                         const DataMap&,
                                                         DataMap&) const {
     if (src->Sem().Module()->Extensions().Contains(
-            ast::Extension::kChromiumDisableUniformityAnalysis)) {
+            builtin::Extension::kChromiumDisableUniformityAnalysis)) {
         return SkipTransform;
     }
 
     ProgramBuilder b;
     CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
-    b.Enable(ast::Extension::kChromiumDisableUniformityAnalysis);
+    b.Enable(builtin::Extension::kChromiumDisableUniformityAnalysis);
 
     ctx.Clone();
     return Program(std::move(b));
diff --git a/src/tint/transform/first_index_offset.cc b/src/tint/transform/first_index_offset.cc
index afc946d..e739fae 100644
--- a/src/tint/transform/first_index_offset.cc
+++ b/src/tint/transform/first_index_offset.cc
@@ -88,13 +88,13 @@
         if (auto* var = node->As<ast::Variable>()) {
             for (auto* attr : var->attributes) {
                 if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
-                    ast::BuiltinValue builtin = builtin_attr->builtin;
-                    if (builtin == ast::BuiltinValue::kVertexIndex) {
+                    builtin::BuiltinValue builtin = builtin_attr->builtin;
+                    if (builtin == builtin::BuiltinValue::kVertexIndex) {
                         auto* sem_var = ctx.src->Sem().Get(var);
                         builtin_vars.emplace(sem_var, kFirstVertexName);
                         has_vertex_or_instance_index = true;
                     }
-                    if (builtin == ast::BuiltinValue::kInstanceIndex) {
+                    if (builtin == builtin::BuiltinValue::kInstanceIndex) {
                         auto* sem_var = ctx.src->Sem().Get(var);
                         builtin_vars.emplace(sem_var, kFirstInstanceName);
                         has_vertex_or_instance_index = true;
@@ -105,13 +105,13 @@
         if (auto* member = node->As<ast::StructMember>()) {
             for (auto* attr : member->attributes) {
                 if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
-                    ast::BuiltinValue builtin = builtin_attr->builtin;
-                    if (builtin == ast::BuiltinValue::kVertexIndex) {
+                    builtin::BuiltinValue builtin = builtin_attr->builtin;
+                    if (builtin == builtin::BuiltinValue::kVertexIndex) {
                         auto* sem_mem = ctx.src->Sem().Get(member);
                         builtin_members.emplace(sem_mem, kFirstVertexName);
                         has_vertex_or_instance_index = true;
                     }
-                    if (builtin == ast::BuiltinValue::kInstanceIndex) {
+                    if (builtin == builtin::BuiltinValue::kInstanceIndex) {
                         auto* sem_mem = ctx.src->Sem().Get(member);
                         builtin_members.emplace(sem_mem, kFirstInstanceName);
                         has_vertex_or_instance_index = true;
diff --git a/src/tint/transform/num_workgroups_from_uniform.cc b/src/tint/transform/num_workgroups_from_uniform.cc
index 72b32df..35e59fb 100644
--- a/src/tint/transform/num_workgroups_from_uniform.cc
+++ b/src/tint/transform/num_workgroups_from_uniform.cc
@@ -33,7 +33,7 @@
 bool ShouldRun(const Program* program) {
     for (auto* node : program->ASTNodes().Objects()) {
         if (auto* attr = node->As<ast::BuiltinAttribute>()) {
-            if (attr->builtin == ast::BuiltinValue::kNumWorkgroups) {
+            if (attr->builtin == builtin::BuiltinValue::kNumWorkgroups) {
                 return true;
             }
         }
@@ -100,7 +100,7 @@
             for (auto* member : str->Members()) {
                 auto* builtin =
                     ast::GetAttribute<ast::BuiltinAttribute>(member->Declaration()->attributes);
-                if (!builtin || builtin->builtin != ast::BuiltinValue::kNumWorkgroups) {
+                if (!builtin || builtin->builtin != builtin::BuiltinValue::kNumWorkgroups) {
                     continue;
                 }
 
diff --git a/src/tint/transform/preserve_padding.cc b/src/tint/transform/preserve_padding.cc
index 011e5c9..ba30933 100644
--- a/src/tint/transform/preserve_padding.cc
+++ b/src/tint/transform/preserve_padding.cc
@@ -66,7 +66,7 @@
                 [&](const ast::Enable* enable) {
                     // Check if the full pointer parameters extension is already enabled.
                     if (enable->extension ==
-                        ast::Extension::kChromiumExperimentalFullPtrParameters) {
+                        builtin::Extension::kChromiumExperimentalFullPtrParameters) {
                         ext_enabled = true;
                     }
                 });
@@ -197,7 +197,7 @@
     /// Enable the full pointer parameters extension, if we have not already done so.
     void EnableExtension() {
         if (!ext_enabled) {
-            b.Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
+            b.Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
             ext_enabled = true;
         }
     }
diff --git a/src/tint/transform/renamer_test.cc b/src/tint/transform/renamer_test.cc
index 71cf2a2..c233267 100644
--- a/src/tint/transform/renamer_test.cc
+++ b/src/tint/transform/renamer_test.cc
@@ -1571,60 +1571,99 @@
         kUnicodeIdentifier));
 
 std::string ExpandBuiltinType(std::string_view name) {
+    if (name == "array") {
+        return "array<i32, 4>";
+    }
+    if (name == "atomic") {
+        return "atomic<i32>";
+    }
+    if (name == "mat2x2") {
+        return "mat2x2<f32>";
+    }
     if (name == "mat2x2f") {
         return "mat2x2<f32>";
     }
     if (name == "mat2x2h") {
         return "mat2x2<f16>";
     }
+    if (name == "mat2x3") {
+        return "mat2x3<f32>";
+    }
     if (name == "mat2x3f") {
         return "mat2x3<f32>";
     }
     if (name == "mat2x3h") {
         return "mat2x3<f16>";
     }
+    if (name == "mat2x4") {
+        return "mat2x4<f32>";
+    }
     if (name == "mat2x4f") {
         return "mat2x4<f32>";
     }
     if (name == "mat2x4h") {
         return "mat2x4<f16>";
     }
+    if (name == "mat3x2") {
+        return "mat3x2<f32>";
+    }
     if (name == "mat3x2f") {
         return "mat3x2<f32>";
     }
     if (name == "mat3x2h") {
         return "mat3x2<f16>";
     }
+    if (name == "mat3x3") {
+        return "mat3x3<f32>";
+    }
     if (name == "mat3x3f") {
         return "mat3x3<f32>";
     }
     if (name == "mat3x3h") {
         return "mat3x3<f16>";
     }
+    if (name == "mat3x4") {
+        return "mat3x4<f32>";
+    }
     if (name == "mat3x4f") {
         return "mat3x4<f32>";
     }
     if (name == "mat3x4h") {
         return "mat3x4<f16>";
     }
+    if (name == "mat4x2") {
+        return "mat4x2<f32>";
+    }
     if (name == "mat4x2f") {
         return "mat4x2<f32>";
     }
     if (name == "mat4x2h") {
         return "mat4x2<f16>";
     }
+    if (name == "mat4x3") {
+        return "mat4x3<f32>";
+    }
     if (name == "mat4x3f") {
         return "mat4x3<f32>";
     }
     if (name == "mat4x3h") {
         return "mat4x3<f16>";
     }
+    if (name == "mat4x4") {
+        return "mat4x4<f32>";
+    }
     if (name == "mat4x4f") {
         return "mat4x4<f32>";
     }
     if (name == "mat4x4h") {
         return "mat4x4<f16>";
     }
+    if (name == "ptr") {
+        return "ptr<function, i32>";
+    }
+    if (name == "vec2") {
+        return "vec2<f32>";
+    }
     if (name == "vec2f") {
         return "vec2<f32>";
     }
@@ -1637,6 +1676,9 @@
     if (name == "vec2u") {
         return "vec2<u32>";
     }
+    if (name == "vec3") {
+        return "vec3<f32>";
+    }
     if (name == "vec3f") {
         return "vec3<f32>";
     }
@@ -1649,6 +1691,9 @@
     if (name == "vec3u") {
         return "vec3<u32>";
     }
+    if (name == "vec4") {
+        return "vec4<f32>";
+    }
     if (name == "vec4f") {
         return "vec4<f32>";
     }
@@ -1664,58 +1709,13 @@
     return std::string(name);
 }
 
-/// @return all the identifiers parsed as keywords
-std::unordered_set<std::string> Keywords() {
-    return {
-        "array",
-        "atomic",
-        "bool",
-        "f16",
-        "f32",
-        "i32",
-        "mat2x2",
-        "mat2x3",
-        "mat2x4",
-        "mat3x2",
-        "mat3x3",
-        "mat3x4",
-        "mat4x2",
-        "mat4x3",
-        "mat4x4",
-        "ptr",
-        "sampler_comparison",
-        "sampler",
-        "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",
-        "u32",
-        "vec2",
-        "vec3",
-        "vec4",
-    };
-}
-
-/// @return WGSL builtin types that aren't keywords
-std::vector<const char*> NonKeywordBuiltinTypes() {
-    auto keywords = Keywords();
+std::vector<const char*> ConstructableTypes() {
     std::vector<const char*> out;
-    for (auto* ident : type::kBuiltinStrings) {
-        if (!keywords.count(ident)) {
-            out.push_back(ident);
+    for (auto* ty : type::kBuiltinStrings) {
+        std::string_view type(ty);
+        if (type != "ptr" && type != "atomic" && !utils::HasPrefix(type, "sampler") &&
+            !utils::HasPrefix(type, "texture")) {
+            out.push_back(ty);
         }
     }
     return out;
@@ -1725,38 +1725,36 @@
 
 TEST_P(RenamerBuiltinTypeTest, PreserveTypeUsage) {
     auto expand = [&](const char* source) {
-        auto out = utils::ReplaceAll(source, "$name", GetParam());
-        out = utils::ReplaceAll(out, "$type", ExpandBuiltinType(GetParam()));
-        return out;
+        return utils::ReplaceAll(source, "$type", ExpandBuiltinType(GetParam()));
     };
 
     auto src = expand(R"(
 enable f16;
 
-fn x(v : $name) -> $name {
-  const a : $name = $name();
-  let b : $name = a;
-  var c : $name = b;
+fn x(v : $type) -> $type {
+  const a : $type = $type();
+  let b : $type = a;
+  var c : $type = b;
   return c;
 }
 
 struct y {
-  a : $name,
+  a : $type,
 }
 )");
 
     auto expect = expand(R"(
 enable f16;
 
-fn tint_symbol(tint_symbol_1 : $name) -> $name {
-  const tint_symbol_2 : $name = $name();
-  let tint_symbol_3 : $name = tint_symbol_2;
-  var tint_symbol_4 : $name = tint_symbol_3;
+fn tint_symbol(tint_symbol_1 : $type) -> $type {
+  const tint_symbol_2 : $type = $type();
+  let tint_symbol_3 : $type = tint_symbol_2;
+  var tint_symbol_4 : $type = tint_symbol_3;
   return tint_symbol_4;
 }
 
 struct tint_symbol_5 {
-  tint_symbol_2 : $name,
+  tint_symbol_2 : $type,
 }
 )");
 
@@ -1766,9 +1764,7 @@
 }
 TEST_P(RenamerBuiltinTypeTest, PreserveTypeInitializer) {
     auto expand = [&](const char* source) {
-        auto out = utils::ReplaceAll(source, "$name", GetParam());
-        out = utils::ReplaceAll(out, "$type", ExpandBuiltinType(GetParam()));
-        return out;
+        return utils::ReplaceAll(source, "$type", ExpandBuiltinType(GetParam()));
     };
 
     auto src = expand(R"(
@@ -1776,7 +1772,7 @@
 
 @fragment
 fn f() {
-  var v : $type = $name();
+  var v : $type = $type();
 }
 )");
 
@@ -1785,7 +1781,7 @@
 
 @fragment
 fn tint_symbol() {
-  var tint_symbol_1 : $type = $name();
+  var tint_symbol_1 : $type = $type();
 }
 )");
 
@@ -1795,10 +1791,12 @@
 }
 
 TEST_P(RenamerBuiltinTypeTest, PreserveTypeConversion) {
+    if (std::string_view(GetParam()) == "array") {
+        return;  // Cannot type convert arrays.
+    }
+
     auto expand = [&](const char* source) {
-        auto out = utils::ReplaceAll(source, "$name", GetParam());
-        out = utils::ReplaceAll(out, "$type", ExpandBuiltinType(GetParam()));
-        return out;
+        return utils::ReplaceAll(source, "$type", ExpandBuiltinType(GetParam()));
     };
 
     auto src = expand(R"(
@@ -1806,7 +1804,7 @@
 
 @fragment
 fn f() {
-  var v : $type = $name($type());
+  var v : $type = $type($type());
 }
 )");
 
@@ -1815,7 +1813,7 @@
 
 @fragment
 fn tint_symbol() {
-  var tint_symbol_1 : $type = $name($type());
+  var tint_symbol_1 : $type = $type($type());
 }
 )");
 
@@ -1850,26 +1848,28 @@
 
 TEST_P(RenamerBuiltinTypeTest, RenameShadowedByAlias) {
     auto expand = [&](const char* source) {
-        auto out = utils::ReplaceAll(source, "$name", GetParam());
-        out = utils::ReplaceAll(out, "$type", ExpandBuiltinType(GetParam()));
+        std::string_view ty = GetParam();
+        auto out = utils::ReplaceAll(source, "$name", ty);
+        out = utils::ReplaceAll(out, "$type", ExpandBuiltinType(ty));
+        out = utils::ReplaceAll(out, "$other_type", ty == "i32" ? "u32" : "i32");
         return out;
     };
 
     auto src = expand(R"(
-type $name = i32;
+type $name = $other_type;
 
 @fragment
 fn f() {
-  var v : i32 = $name();
+  var v : $other_type = $name();
 }
 )");
 
     auto expect = expand(R"(
-alias tint_symbol = i32;
+alias tint_symbol = $other_type;
 
 @fragment
 fn tint_symbol_1() {
-  var tint_symbol_2 : i32 = tint_symbol();
+  var tint_symbol_2 : $other_type = tint_symbol();
 }
 )");
 
@@ -1880,14 +1880,16 @@
 
 TEST_P(RenamerBuiltinTypeTest, RenameShadowedByStruct) {
     auto expand = [&](const char* source) {
-        auto out = utils::ReplaceAll(source, "$name", GetParam());
-        out = utils::ReplaceAll(out, "$type", ExpandBuiltinType(GetParam()));
+        std::string_view ty = GetParam();
+        auto out = utils::ReplaceAll(source, "$name", ty);
+        out = utils::ReplaceAll(out, "$type", ExpandBuiltinType(ty));
+        out = utils::ReplaceAll(out, "$other_type", ty == "i32" ? "u32" : "i32");
         return out;
     };
 
     auto src = expand(R"(
 struct $name {
-  i : i32,
+  i : $other_type,
 }
 
 @fragment
@@ -1899,7 +1901,7 @@
 
     auto expect = expand(R"(
 struct tint_symbol {
-  tint_symbol_1 : i32,
+  tint_symbol_1 : $other_type,
 }
 
 @fragment
@@ -1916,31 +1918,22 @@
 
 INSTANTIATE_TEST_SUITE_P(RenamerBuiltinTypeTest,
                          RenamerBuiltinTypeTest,
-                         testing::ValuesIn(NonKeywordBuiltinTypes()));
+                         testing::ValuesIn(ConstructableTypes()));
 
-/// @return WGSL builtin identifiers keywords
-std::vector<const char*> NonKeywordIdentifiers() {
-    auto keywords = Keywords();
+/// @return WGSL builtin identifier keywords
+std::vector<const char*> Identifiers() {
     std::vector<const char*> out;
     for (auto* ident : type::kBuiltinStrings) {
-        if (!keywords.count(ident)) {
-            out.push_back(ident);
-        }
+        out.push_back(ident);
     }
     for (auto* ident : type::kAddressSpaceStrings) {
-        if (!keywords.count(ident)) {
-            out.push_back(ident);
-        }
+        out.push_back(ident);
     }
     for (auto* ident : type::kTexelFormatStrings) {
-        if (!keywords.count(ident)) {
-            out.push_back(ident);
-        }
+        out.push_back(ident);
     }
     for (auto* ident : type::kAccessStrings) {
-        if (!keywords.count(ident)) {
-            out.push_back(ident);
-        }
+        out.push_back(ident);
     }
     return out;
 }
@@ -2025,12 +2018,14 @@
 
 TEST_P(RenamerBuiltinIdentifierTest, StructName) {
     auto expand = [&](const char* source) {
-        return utils::ReplaceAll(source, "$name", GetParam());
+        std::string_view name = GetParam();
+        auto out = utils::ReplaceAll(source, "$name", name);
+        return utils::ReplaceAll(out, "$other_type", name == "i32" ? "u32" : "i32");
     };
 
     auto src = expand(R"(
 struct $name {
-  i : i32,
+  i : $other_type,
 }
 
 fn f() {
@@ -2040,7 +2035,7 @@
 
     auto expect = expand(R"(
 struct tint_symbol {
-  tint_symbol_1 : i32,
+  tint_symbol_1 : $other_type,
 }
 
 fn tint_symbol_2() {
@@ -2055,7 +2050,7 @@
 
 INSTANTIATE_TEST_SUITE_P(RenamerBuiltinIdentifierTest,
                          RenamerBuiltinIdentifierTest,
-                         testing::ValuesIn(NonKeywordIdentifiers()));
+                         testing::ValuesIn(Identifiers()));
 
 }  // namespace
 }  // namespace tint::transform
diff --git a/src/tint/transform/vertex_pulling.cc b/src/tint/transform/vertex_pulling.cc
index 11984cd..8d151bf 100644
--- a/src/tint/transform/vertex_pulling.cc
+++ b/src/tint/transform/vertex_pulling.cc
@@ -778,11 +778,11 @@
                 return;
             }
             // Check for existing vertex_index and instance_index builtins.
-            if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
+            if (builtin->builtin == builtin::BuiltinValue::kVertexIndex) {
                 vertex_index_expr = [this, param]() {
                     return b.Expr(ctx.Clone(param->name->symbol));
                 };
-            } else if (builtin->builtin == ast::BuiltinValue::kInstanceIndex) {
+            } else if (builtin->builtin == builtin::BuiltinValue::kInstanceIndex) {
                 instance_index_expr = [this, param]() {
                     return b.Expr(ctx.Clone(param->name->symbol));
                 };
@@ -831,9 +831,9 @@
                     return;
                 }
                 // Check for existing vertex_index and instance_index builtins.
-                if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
+                if (builtin->builtin == builtin::BuiltinValue::kVertexIndex) {
                     vertex_index_expr = member_expr;
-                } else if (builtin->builtin == ast::BuiltinValue::kInstanceIndex) {
+                } else if (builtin->builtin == builtin::BuiltinValue::kInstanceIndex) {
                     instance_index_expr = member_expr;
                 }
                 members_to_clone.Push(member);
@@ -899,7 +899,7 @@
                     auto name = b.Symbols().New("tint_pulling_vertex_index");
                     new_function_parameters.Push(
                         b.Param(name, b.ty.u32(),
-                                utils::Vector{b.Builtin(ast::BuiltinValue::kVertexIndex)}));
+                                utils::Vector{b.Builtin(builtin::BuiltinValue::kVertexIndex)}));
                     vertex_index_expr = [this, name]() { return b.Expr(name); };
                     break;
                 }
@@ -911,7 +911,7 @@
                     auto name = b.Symbols().New("tint_pulling_instance_index");
                     new_function_parameters.Push(
                         b.Param(name, b.ty.u32(),
-                                utils::Vector{b.Builtin(ast::BuiltinValue::kInstanceIndex)}));
+                                utils::Vector{b.Builtin(builtin::BuiltinValue::kInstanceIndex)}));
                     instance_index_expr = [this, name]() { return b.Expr(name); };
                     break;
                 }
diff --git a/src/tint/transform/zero_init_workgroup_memory.cc b/src/tint/transform/zero_init_workgroup_memory.cc
index e4943a7..49d96d9 100644
--- a/src/tint/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/transform/zero_init_workgroup_memory.cc
@@ -159,7 +159,7 @@
         std::function<const ast::Expression*()> local_index;
         for (auto* param : fn->params) {
             if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
-                if (builtin->builtin == ast::BuiltinValue::kLocalInvocationIndex) {
+                if (builtin->builtin == builtin::BuiltinValue::kLocalInvocationIndex) {
                     local_index = [=] { return b.Expr(ctx.Clone(param->name->symbol)); };
                     break;
                 }
@@ -169,7 +169,7 @@
                 for (auto* member : str->Members()) {
                     if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(
                             member->Declaration()->attributes)) {
-                        if (builtin->builtin == ast::BuiltinValue::kLocalInvocationIndex) {
+                        if (builtin->builtin == builtin::BuiltinValue::kLocalInvocationIndex) {
                             local_index = [=] {
                                 auto* param_expr = b.Expr(ctx.Clone(param->name->symbol));
                                 auto* member_name = ctx.Clone(member->Declaration()->name);
@@ -185,7 +185,7 @@
             // 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(ast::BuiltinValue::kLocalInvocationIndex),
+                                      b.Builtin(builtin::BuiltinValue::kLocalInvocationIndex),
                                   });
             ctx.InsertBack(fn->params, param);
             local_index = [=] { return b.Expr(param->name->symbol); };
diff --git a/src/tint/writer/check_supported_extensions.cc b/src/tint/writer/check_supported_extensions.cc
index 3bb16bf..bde86a5 100644
--- a/src/tint/writer/check_supported_extensions.cc
+++ b/src/tint/writer/check_supported_extensions.cc
@@ -26,8 +26,8 @@
 bool CheckSupportedExtensions(std::string_view writer_name,
                               const ast::Module& module,
                               diag::List& diags,
-                              utils::VectorRef<ast::Extension> supported) {
-    utils::Hashset<ast::Extension, 32> set;
+                              utils::VectorRef<builtin::Extension> supported) {
+    utils::Hashset<builtin::Extension, 32> set;
     for (auto ext : supported) {
         set.Add(ext);
     }
diff --git a/src/tint/writer/check_supported_extensions.h b/src/tint/writer/check_supported_extensions.h
index c1884d0..8776102 100644
--- a/src/tint/writer/check_supported_extensions.h
+++ b/src/tint/writer/check_supported_extensions.h
@@ -15,7 +15,7 @@
 #ifndef SRC_TINT_WRITER_CHECK_SUPPORTED_EXTENSIONS_H_
 #define SRC_TINT_WRITER_CHECK_SUPPORTED_EXTENSIONS_H_
 
-#include "src/tint/ast/extension.h"
+#include "src/tint/builtin/extension.h"
 #include "src/tint/utils/vector.h"
 
 namespace tint::ast {
@@ -36,7 +36,7 @@
 bool CheckSupportedExtensions(std::string_view writer_name,
                               const ast::Module& module,
                               diag::List& diags,
-                              utils::VectorRef<ast::Extension> supported);
+                              utils::VectorRef<builtin::Extension> supported);
 
 }  // namespace tint::writer
 
diff --git a/src/tint/writer/check_supported_extensions_test.cc b/src/tint/writer/check_supported_extensions_test.cc
index 97c3b32..4d5690b 100644
--- a/src/tint/writer/check_supported_extensions_test.cc
+++ b/src/tint/writer/check_supported_extensions_test.cc
@@ -24,21 +24,21 @@
 class CheckSupportedExtensionsTest : public ::testing::Test, public ProgramBuilder {};
 
 TEST_F(CheckSupportedExtensionsTest, Supported) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     ASSERT_TRUE(CheckSupportedExtensions("writer", AST(), Diagnostics(),
                                          utils::Vector{
-                                             ast::Extension::kF16,
-                                             ast::Extension::kChromiumExperimentalDp4A,
+                                             builtin::Extension::kF16,
+                                             builtin::Extension::kChromiumExperimentalDp4A,
                                          }));
 }
 
 TEST_F(CheckSupportedExtensionsTest, Unsupported) {
-    Enable(Source{{12, 34}}, ast::Extension::kF16);
+    Enable(Source{{12, 34}}, builtin::Extension::kF16);
 
     ASSERT_FALSE(CheckSupportedExtensions("writer", AST(), Diagnostics(),
                                           utils::Vector{
-                                              ast::Extension::kChromiumExperimentalDp4A,
+                                              builtin::Extension::kChromiumExperimentalDp4A,
                                           }));
     EXPECT_EQ(Diagnostics().str(), "12:34 error: writer backend does not support extension 'f16'");
 }
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 5847923..a09af2f 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -90,10 +90,10 @@
            op == tint::ast::BinaryOp::kGreaterThanEqual;
 }
 
-bool RequiresOESSampleVariables(tint::ast::BuiltinValue builtin) {
+bool RequiresOESSampleVariables(tint::builtin::BuiltinValue builtin) {
     switch (builtin) {
-        case tint::ast::BuiltinValue::kSampleIndex:
-        case tint::ast::BuiltinValue::kSampleMask:
+        case tint::builtin::BuiltinValue::kSampleIndex:
+        case tint::builtin::BuiltinValue::kSampleMask:
             return true;
         default:
             return false;
@@ -326,7 +326,7 @@
 bool GeneratorImpl::RecordExtension(const ast::Enable* ext) {
     // Deal with extension node here, recording it within the generator for later emition.
 
-    if (ext->extension == ast::Extension::kF16) {
+    if (ext->extension == builtin::Extension::kF16) {
         requires_f16_extension_ = true;
     }
 
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index e972b12..71fb23e 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -471,11 +471,11 @@
     /// @param builtin the builtin to convert
     /// @param stage pipeline stage in which this builtin is used
     /// @returns the string name of the builtin or blank on error
-    const char* builtin_to_string(ast::BuiltinValue builtin, ast::PipelineStage stage);
+    const char* builtin_to_string(builtin::BuiltinValue builtin, ast::PipelineStage stage);
     /// Converts a builtin to a type::Type appropriate for GLSL.
     /// @param builtin the builtin to convert
     /// @returns the appropriate semantic type or null on error.
-    type::Type* builtin_type(ast::BuiltinValue builtin);
+    type::Type* builtin_type(builtin::BuiltinValue builtin);
 
   private:
     enum class VarType { kIn, kOut };
diff --git a/src/tint/writer/glsl/generator_impl_binary_test.cc b/src/tint/writer/glsl/generator_impl_binary_test.cc
index 884cba0..72eddc7 100644
--- a/src/tint/writer/glsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/glsl/generator_impl_binary_test.cc
@@ -69,7 +69,7 @@
         return;
     }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("left", ty.f16(), type::AddressSpace::kPrivate);
     GlobalVar("right", ty.f16(), type::AddressSpace::kPrivate);
@@ -167,7 +167,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", vec3<f16>(1_h, 1_h, 1_h), type::AddressSpace::kPrivate);
     auto* lhs = Expr("a");
@@ -201,7 +201,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", vec3<f16>(1_h, 1_h, 1_h), type::AddressSpace::kPrivate);
     auto* lhs = Expr(1_h);
@@ -234,7 +234,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
@@ -266,7 +266,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* lhs = Expr(1_h);
@@ -298,7 +298,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
@@ -330,7 +330,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
@@ -361,7 +361,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("lhs", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     GlobalVar("rhs", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
@@ -391,7 +391,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModF16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.f16(), type::AddressSpace::kPrivate);
     GlobalVar("b", ty.f16(), type::AddressSpace::kPrivate);
@@ -421,7 +421,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModVec3F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate);
     GlobalVar("b", ty.vec3<f16>(), type::AddressSpace::kPrivate);
@@ -451,7 +451,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModVec3F16ScalarF16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate);
     GlobalVar("b", ty.f16(), type::AddressSpace::kPrivate);
@@ -481,7 +481,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModScalarF16Vec3F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.f16(), type::AddressSpace::kPrivate);
     GlobalVar("b", ty.vec3<f16>(), type::AddressSpace::kPrivate);
@@ -539,7 +539,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModMixedVec3ScalarF16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate);
     GlobalVar("b", ty.f16(), type::AddressSpace::kPrivate);
diff --git a/src/tint/writer/glsl/generator_impl_builtin_test.cc b/src/tint/writer/glsl/generator_impl_builtin_test.cc
index 33d2fa7..7526494 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_test.cc
@@ -196,7 +196,7 @@
     auto param = GetParam();
 
     if (param.type == CallParamType::kF16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
 
         GlobalVar("h2", ty.vec2<f16>(), type::AddressSpace::kPrivate);
         GlobalVar("h3", ty.vec3<f16>(), type::AddressSpace::kPrivate);
@@ -399,7 +399,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, FMA_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("a", ty.vec3<f16>(), type::AddressSpace::kPrivate);
     GlobalVar("b", ty.vec3<f16>(), type::AddressSpace::kPrivate);
@@ -451,7 +451,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Runtime_Modf_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("f", Expr(1.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
@@ -522,7 +522,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Runtime_Modf_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("f", vec3<f16>(1.5_h, 2.5_h, 3.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
@@ -585,7 +585,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Const_Modf_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("modf", 1.5_h))));
 
@@ -640,7 +640,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Const_Modf_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("modf", vec3<f16>(1.5_h, 2.5_h, 3.5_h)))));
 
@@ -703,7 +703,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Runtime_Frexp_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Var("f", Expr(1_h)),  //
                    Var("v", Call("frexp", "f")));
@@ -774,7 +774,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Runtime_Frexp_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Var("f", Expr(vec3<f16>())),  //
                    Var("v", Call("frexp", "f")));
@@ -837,7 +837,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Const_Frexp_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("frexp", 1_h))));
 
@@ -892,7 +892,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Const_Frexp_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("frexp", vec3<f16>()))));
 
@@ -977,7 +977,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.f16());
     auto* call = Call("degrees", val);
@@ -1008,7 +1008,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.vec3<f16>());
     auto* call = Call("degrees", val);
@@ -1095,7 +1095,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Radians_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.f16());
     auto* call = Call("radians", val);
@@ -1126,7 +1126,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Radians_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.vec3<f16>());
     auto* call = Call("radians", val);
diff --git a/src/tint/writer/glsl/generator_impl_function_test.cc b/src/tint/writer/glsl/generator_impl_function_test.cc
index db16749..2d1ed02 100644
--- a/src/tint/writer/glsl/generator_impl_function_test.cc
+++ b/src/tint/writer/glsl/generator_impl_function_test.cc
@@ -166,7 +166,7 @@
     //   return coord.x;
     // }
     auto* coord_in =
-        Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
+        Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
     Func("frag_main",
          utils::Vector{
              coord_in,
@@ -179,7 +179,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kFragDepth),
+             Builtin(builtin::BuiltinValue::kFragDepth),
          });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -217,7 +217,7 @@
     auto* interface_struct = Structure(
         "Interface",
         utils::Vector{
-            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
             Member("col1", ty.f32(), utils::Vector{Location(1_a)}),
             Member("col2", ty.f32(), utils::Vector{Location(2_a)}),
         });
@@ -297,7 +297,7 @@
   // }
   auto* vertex_output_struct = Structure(
       "VertexOutput",
-      {Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)})});
+      {Member("pos", ty.vec4<f32>(), {Builtin(builtin::BuiltinValue::kPosition)})});
 
   Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
        {Return(Call(ty.Of(vertex_output_struct),
diff --git a/src/tint/writer/glsl/generator_impl_initializer_test.cc b/src/tint/writer/glsl/generator_impl_initializer_test.cc
index e9c4dc9..d62942d 100644
--- a/src/tint/writer/glsl/generator_impl_initializer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_initializer_test.cc
@@ -62,7 +62,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
     WrapInFunction(Expr(f16((1 << 15) - 8)));
@@ -83,7 +83,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Call<f16>(-1.2e-3_h));
 
@@ -130,7 +130,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
 
@@ -150,7 +150,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_Empty_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>());
 
@@ -170,7 +170,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F16_Literal) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(2_h));
 
@@ -193,7 +193,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F16_Var) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
     auto* cast = vec3<f16>(var);
@@ -244,7 +244,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
 
@@ -290,7 +290,7 @@
     //     vec4<f16>(7.0h),
     //     vec4<f16>(vec4<f16>(42.0h, 21.0h, 6.0h, -5.0h)),
     //   );
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vector_literal =
         vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
@@ -324,7 +324,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Empty_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>());
 
@@ -360,7 +360,7 @@
     //     var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
     // }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
     auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
diff --git a/src/tint/writer/glsl/generator_impl_module_constant_test.cc b/src/tint/writer/glsl/generator_impl_module_constant_test.cc
index 9f0985d..dfbcecf 100644
--- a/src/tint/writer/glsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/glsl/generator_impl_module_constant_test.cc
@@ -133,7 +133,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", Expr(1_h));
     Func("f", utils::Empty, ty.void_(),
@@ -216,7 +216,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", vec3<f16>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(),
@@ -279,7 +279,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(),
diff --git a/src/tint/writer/glsl/generator_impl_test.cc b/src/tint/writer/glsl/generator_impl_test.cc
index abb391f..b449253 100644
--- a/src/tint/writer/glsl/generator_impl_test.cc
+++ b/src/tint/writer/glsl/generator_impl_test.cc
@@ -59,7 +59,7 @@
 TEST_F(GlslGeneratorImplTest, GenerateSampleIndexES) {
     GlobalVar("gl_SampleID", ty.i32(),
               utils::Vector{
-                  Builtin(ast::BuiltinValue::kSampleIndex),
+                  Builtin(builtin::BuiltinValue::kSampleIndex),
                   Disable(ast::DisabledValidation::kIgnoreAddressSpace),
               },
               type::AddressSpace::kIn);
@@ -84,7 +84,7 @@
 TEST_F(GlslGeneratorImplTest, GenerateSampleIndexDesktop) {
     GlobalVar("gl_SampleID", ty.i32(),
               utils::Vector{
-                  Builtin(ast::BuiltinValue::kSampleIndex),
+                  Builtin(builtin::BuiltinValue::kSampleIndex),
                   Disable(ast::DisabledValidation::kIgnoreAddressSpace),
               },
               type::AddressSpace::kIn);
diff --git a/src/tint/writer/glsl/generator_impl_type_test.cc b/src/tint/writer/glsl/generator_impl_type_test.cc
index 625c7d3..b538979 100644
--- a/src/tint/writer/glsl/generator_impl_type_test.cc
+++ b/src/tint/writer/glsl/generator_impl_type_test.cc
@@ -107,7 +107,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* f16 = create<type::F16>();
 
@@ -144,7 +144,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Matrix_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* f16 = create<type::F16>();
     auto* vec3 = create<type::Vector>(f16, 3u);
@@ -255,7 +255,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Vector_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* f16 = create<type::F16>();
     auto* vec3 = create<type::Vector>(f16, 3u);
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 6511179..a4d11cb 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
@@ -170,7 +170,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", Expr(1_h));
     Func("f", utils::Empty, ty.void_(),
@@ -257,7 +257,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", vec3<f16>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(),
@@ -323,7 +323,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(),
@@ -501,7 +501,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("a", ty.vec3<f16>(), vec3<f16>());
 
@@ -530,7 +530,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("a", ty.mat2x3<f16>(), mat2x3<f16>());
 
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 4e37faa..aab30d2 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -297,11 +297,11 @@
 bool GeneratorImpl::Generate() {
     if (!CheckSupportedExtensions("HLSL", program_->AST(), diagnostics_,
                                   utils::Vector{
-                                      ast::Extension::kChromiumDisableUniformityAnalysis,
-                                      ast::Extension::kChromiumExperimentalDp4A,
-                                      ast::Extension::kChromiumExperimentalFullPtrParameters,
-                                      ast::Extension::kChromiumExperimentalPushConstant,
-                                      ast::Extension::kF16,
+                                      builtin::Extension::kChromiumDisableUniformityAnalysis,
+                                      builtin::Extension::kChromiumExperimentalDp4A,
+                                      builtin::Extension::kChromiumExperimentalFullPtrParameters,
+                                      builtin::Extension::kChromiumExperimentalPushConstant,
+                                      builtin::Extension::kF16,
                                   })) {
         return false;
     }
@@ -1166,7 +1166,7 @@
         }
     }
 
-    constexpr const char swizzle[] = {'x', 'y', 'z', 'w'};
+    const char swizzle[] = {'x', 'y', 'z', 'w'};
 
     using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
     using DataType = transform::DecomposeMemoryAccess::Intrinsic::DataType;
@@ -3154,29 +3154,29 @@
     return true;
 }
 
-std::string GeneratorImpl::builtin_to_attribute(ast::BuiltinValue builtin) const {
+std::string GeneratorImpl::builtin_to_attribute(builtin::BuiltinValue builtin) const {
     switch (builtin) {
-        case ast::BuiltinValue::kPosition:
+        case builtin::BuiltinValue::kPosition:
             return "SV_Position";
-        case ast::BuiltinValue::kVertexIndex:
+        case builtin::BuiltinValue::kVertexIndex:
             return "SV_VertexID";
-        case ast::BuiltinValue::kInstanceIndex:
+        case builtin::BuiltinValue::kInstanceIndex:
             return "SV_InstanceID";
-        case ast::BuiltinValue::kFrontFacing:
+        case builtin::BuiltinValue::kFrontFacing:
             return "SV_IsFrontFace";
-        case ast::BuiltinValue::kFragDepth:
+        case builtin::BuiltinValue::kFragDepth:
             return "SV_Depth";
-        case ast::BuiltinValue::kLocalInvocationId:
+        case builtin::BuiltinValue::kLocalInvocationId:
             return "SV_GroupThreadID";
-        case ast::BuiltinValue::kLocalInvocationIndex:
+        case builtin::BuiltinValue::kLocalInvocationIndex:
             return "SV_GroupIndex";
-        case ast::BuiltinValue::kGlobalInvocationId:
+        case builtin::BuiltinValue::kGlobalInvocationId:
             return "SV_DispatchThreadID";
-        case ast::BuiltinValue::kWorkgroupId:
+        case builtin::BuiltinValue::kWorkgroupId:
             return "SV_GroupID";
-        case ast::BuiltinValue::kSampleIndex:
+        case builtin::BuiltinValue::kSampleIndex:
             return "SV_SampleIndex";
-        case ast::BuiltinValue::kSampleMask:
+        case builtin::BuiltinValue::kSampleMask:
             return "SV_Coverage";
         default:
             break;
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index 7b2d97f..b5f53bf 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -495,7 +495,7 @@
     /// Converts a builtin to an attribute name
     /// @param builtin the builtin to convert
     /// @returns the string name of the builtin or blank on error
-    std::string builtin_to_attribute(ast::BuiltinValue builtin) const;
+    std::string builtin_to_attribute(builtin::BuiltinValue builtin) const;
 
     /// Converts interpolation attributes to a HLSL modifiers
     /// @param type the interpolation type
diff --git a/src/tint/writer/hlsl/generator_impl_binary_test.cc b/src/tint/writer/hlsl/generator_impl_binary_test.cc
index afc6b8f..325ca67 100644
--- a/src/tint/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_binary_test.cc
@@ -80,7 +80,7 @@
         return;
     }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("left", ty.f16(), type::AddressSpace::kPrivate);
     GlobalVar("right", ty.f16(), type::AddressSpace::kPrivate);
@@ -188,7 +188,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorScalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
     auto* rhs = Expr(1_h);
@@ -220,7 +220,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarVector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* lhs = Expr(1_h);
     auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
@@ -252,7 +252,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixScalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
@@ -284,7 +284,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarMatrix_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* lhs = Expr(1_h);
@@ -316,7 +316,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
@@ -348,7 +348,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
@@ -379,7 +379,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixMatrix_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     GlobalVar("lhs", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     GlobalVar("rhs", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index d5c4188..9811b79 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -195,7 +195,7 @@
     auto param = GetParam();
 
     if (param.type == CallParamType::kF16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
 
         GlobalVar("h2", ty.vec2<f16>(), type::AddressSpace::kPrivate);
         GlobalVar("h3", ty.vec3<f16>(), type::AddressSpace::kPrivate);
@@ -405,7 +405,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Runtime_Modf_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("f", Expr(1.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
@@ -459,7 +459,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Runtime_Modf_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("f", vec3<f16>(1.5_h, 2.5_h, 3.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
@@ -505,7 +505,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Const_Modf_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("modf", 1.5_h))));
 
@@ -543,7 +543,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Const_Modf_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("modf", vec3<f16>(1.5_h, 2.5_h, 3.5_h)))));
 
@@ -616,7 +616,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Runtime_Frexp_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Var("f", Expr(1_h)),  //
                    Var("v", Call("frexp", "f")));
@@ -672,7 +672,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Runtime_Frexp_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Var("f", Expr(vec3<f16>())),  //
                    Var("v", Call("frexp", "f")));
@@ -719,7 +719,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Const_Frexp_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("frexp", 1_h))));
 
@@ -757,7 +757,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Const_Frexp_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("frexp", vec3<f16>()))));
 
@@ -845,7 +845,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.f16());
     auto* call = Call("degrees", val);
@@ -868,7 +868,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.vec3<f16>());
     auto* call = Call("degrees", val);
@@ -933,7 +933,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Radians_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.f16());
     auto* call = Call("radians", val);
@@ -956,7 +956,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Radians_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.vec3<f16>());
     auto* call = Call("radians", val);
@@ -1047,7 +1047,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Sign_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.f16());
     auto* call = Call("sign", val);
@@ -1066,7 +1066,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Sign_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.vec3<f16>());
     auto* call = Call("sign", val);
@@ -1351,7 +1351,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Dot4I8Packed) {
-    Enable(ast::Extension::kChromiumExperimentalDp4A);
+    Enable(builtin::Extension::kChromiumExperimentalDp4A);
 
     auto* val1 = Var("val1", ty.u32());
     auto* val2 = Var("val2", ty.u32());
@@ -1377,7 +1377,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Dot4U8Packed) {
-    Enable(ast::Extension::kChromiumExperimentalDp4A);
+    Enable(builtin::Extension::kChromiumExperimentalDp4A);
 
     auto* val1 = Var("val1", ty.u32());
     auto* val2 = Var("val2", ty.u32());
diff --git a/src/tint/writer/hlsl/generator_impl_function_test.cc b/src/tint/writer/hlsl/generator_impl_function_test.cc
index bf9eb7a..afad67c 100644
--- a/src/tint/writer/hlsl/generator_impl_function_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_function_test.cc
@@ -157,7 +157,7 @@
     //   return coord.x;
     // }
     auto* coord_in =
-        Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
+        Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
     Func("frag_main", utils::Vector{coord_in}, ty.f32(),
          utils::Vector{
              Return(MemberAccessor("coord", "x")),
@@ -166,7 +166,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kFragDepth),
+             Builtin(builtin::BuiltinValue::kFragDepth),
          });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -209,7 +209,7 @@
     auto* interface_struct = Structure(
         "Interface",
         utils::Vector{
-            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
             Member("col1", ty.f32(), utils::Vector{Location(1_a)}),
             Member("col2", ty.f32(), utils::Vector{Location(2_a)}),
         });
@@ -292,7 +292,7 @@
     auto* vertex_output_struct =
         Structure("VertexOutput",
                   utils::Vector{Member("pos", ty.vec4<f32>(),
-                                       utils::Vector{Builtin(ast::BuiltinValue::kPosition)})});
+                                       utils::Vector{Builtin(builtin::BuiltinValue::kPosition)})});
 
     Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
          utils::Vector{
diff --git a/src/tint/writer/hlsl/generator_impl_initializer_test.cc b/src/tint/writer/hlsl/generator_impl_initializer_test.cc
index 14f8c08..ebc206a 100644
--- a/src/tint/writer/hlsl/generator_impl_initializer_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_initializer_test.cc
@@ -62,7 +62,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
     WrapInFunction(Expr(f16((1 << 15) - 8)));
@@ -83,7 +83,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Call<f16>(-1.2e-3_h));
 
@@ -130,7 +130,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
 
@@ -152,7 +152,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_Empty_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>());
 
@@ -172,7 +172,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F16_Literal) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(2_h));
 
@@ -195,7 +195,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Vec_SingleScalar_F16_Var) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
     auto* cast = vec3<f16>(var);
@@ -259,7 +259,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
 
@@ -307,7 +307,7 @@
     //     vec4<f16>(7.0h),
     //     vec4<f16>(vec4<f16>(42.0h, 21.0h, 6.0h, -5.0h)),
     //   );
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vector_literal =
         vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
@@ -344,7 +344,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Initializer, EmitInitializer_Type_Mat_Empty_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>());
 
@@ -380,7 +380,7 @@
     //     var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
     // }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
     auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
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 0bd7ae6..f2607c5 100644
--- a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -165,7 +165,7 @@
 
     auto p = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     SetupStorageBuffer(utils::Vector{
         Member("a", ty.i32()),
@@ -300,7 +300,7 @@
 
     auto p = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* inner = Structure("Inner", utils::Vector{
                                          Member("a", ty.i32()),
@@ -439,7 +439,7 @@
 
     auto p = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     SetupUniformBuffer(utils::Vector{
         Member("a", ty.i32()),
@@ -707,7 +707,7 @@
 
     auto p = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* inner = Structure("Inner", utils::Vector{
                                          Member("a", ty.i32()),
@@ -989,7 +989,7 @@
 
     auto p = GetParam();
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     SetupStorageBuffer(utils::Vector{
         Member("a", ty.i32()),
@@ -1192,7 +1192,7 @@
     // var<storage> data : Data;
     // data.a[2i][1i];
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     SetupStorageBuffer(utils::Vector{
         Member("z", ty.f16()),
@@ -1258,7 +1258,7 @@
     // var<uniform> data : Data;
     // data.a[2i][1i];
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     SetupUniformBuffer(utils::Vector{
         Member("z", ty.f16()),
diff --git a/src/tint/writer/hlsl/generator_impl_module_constant_test.cc b/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
index 62f1d8e..5a9327d 100644
--- a/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
@@ -93,7 +93,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", Expr(1_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
@@ -151,7 +151,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", vec3<f16>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
@@ -195,7 +195,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
diff --git a/src/tint/writer/hlsl/generator_impl_test.cc b/src/tint/writer/hlsl/generator_impl_test.cc
index 8fa1156..eeb9acb 100644
--- a/src/tint/writer/hlsl/generator_impl_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_test.cc
@@ -29,7 +29,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest, UnsupportedExtension) {
-    Enable(Source{{12, 34}}, ast::Extension::kUndefined);
+    Enable(Source{{12, 34}}, builtin::Extension::kUndefined);
 
     GeneratorImpl& gen = Build();
 
@@ -49,7 +49,7 @@
 }
 
 struct HlslBuiltinData {
-    ast::BuiltinValue builtin;
+    builtin::BuiltinValue builtin;
     const char* attribute_name;
 };
 inline std::ostream& operator<<(std::ostream& out, HlslBuiltinData data) {
@@ -66,17 +66,18 @@
 INSTANTIATE_TEST_SUITE_P(
     HlslGeneratorImplTest,
     HlslBuiltinConversionTest,
-    testing::Values(HlslBuiltinData{ast::BuiltinValue::kPosition, "SV_Position"},
-                    HlslBuiltinData{ast::BuiltinValue::kVertexIndex, "SV_VertexID"},
-                    HlslBuiltinData{ast::BuiltinValue::kInstanceIndex, "SV_InstanceID"},
-                    HlslBuiltinData{ast::BuiltinValue::kFrontFacing, "SV_IsFrontFace"},
-                    HlslBuiltinData{ast::BuiltinValue::kFragDepth, "SV_Depth"},
-                    HlslBuiltinData{ast::BuiltinValue::kLocalInvocationId, "SV_GroupThreadID"},
-                    HlslBuiltinData{ast::BuiltinValue::kLocalInvocationIndex, "SV_GroupIndex"},
-                    HlslBuiltinData{ast::BuiltinValue::kGlobalInvocationId, "SV_DispatchThreadID"},
-                    HlslBuiltinData{ast::BuiltinValue::kWorkgroupId, "SV_GroupID"},
-                    HlslBuiltinData{ast::BuiltinValue::kSampleIndex, "SV_SampleIndex"},
-                    HlslBuiltinData{ast::BuiltinValue::kSampleMask, "SV_Coverage"}));
+    testing::Values(HlslBuiltinData{builtin::BuiltinValue::kPosition, "SV_Position"},
+                    HlslBuiltinData{builtin::BuiltinValue::kVertexIndex, "SV_VertexID"},
+                    HlslBuiltinData{builtin::BuiltinValue::kInstanceIndex, "SV_InstanceID"},
+                    HlslBuiltinData{builtin::BuiltinValue::kFrontFacing, "SV_IsFrontFace"},
+                    HlslBuiltinData{builtin::BuiltinValue::kFragDepth, "SV_Depth"},
+                    HlslBuiltinData{builtin::BuiltinValue::kLocalInvocationId, "SV_GroupThreadID"},
+                    HlslBuiltinData{builtin::BuiltinValue::kLocalInvocationIndex, "SV_GroupIndex"},
+                    HlslBuiltinData{builtin::BuiltinValue::kGlobalInvocationId,
+                                    "SV_DispatchThreadID"},
+                    HlslBuiltinData{builtin::BuiltinValue::kWorkgroupId, "SV_GroupID"},
+                    HlslBuiltinData{builtin::BuiltinValue::kSampleIndex, "SV_SampleIndex"},
+                    HlslBuiltinData{builtin::BuiltinValue::kSampleMask, "SV_Coverage"}));
 
 }  // namespace
 }  // namespace tint::writer::hlsl
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 170d993..fedf476 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
@@ -155,7 +155,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", Expr(1_h));
     Func("f", utils::Empty, ty.void_(),
@@ -229,7 +229,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", vec3<f16>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(),
@@ -285,7 +285,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(),
@@ -383,7 +383,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("a", ty.vec3<f16>(), vec3<f16>());
 
@@ -412,7 +412,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("a", ty.mat2x3<f16>(), mat2x3<f16>());
 
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index febde27..87928b4 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -270,10 +270,10 @@
 bool GeneratorImpl::Generate() {
     if (!CheckSupportedExtensions("MSL", program_->AST(), diagnostics_,
                                   utils::Vector{
-                                      ast::Extension::kChromiumDisableUniformityAnalysis,
-                                      ast::Extension::kChromiumExperimentalFullPtrParameters,
-                                      ast::Extension::kChromiumExperimentalPushConstant,
-                                      ast::Extension::kF16,
+                                      builtin::Extension::kChromiumDisableUniformityAnalysis,
+                                      builtin::Extension::kChromiumExperimentalFullPtrParameters,
+                                      builtin::Extension::kChromiumExperimentalPushConstant,
+                                      builtin::Extension::kF16,
                                   })) {
         return false;
     }
@@ -1905,33 +1905,33 @@
     return true;
 }
 
-std::string GeneratorImpl::builtin_to_attribute(ast::BuiltinValue builtin) const {
+std::string GeneratorImpl::builtin_to_attribute(builtin::BuiltinValue builtin) const {
     switch (builtin) {
-        case ast::BuiltinValue::kPosition:
+        case builtin::BuiltinValue::kPosition:
             return "position";
-        case ast::BuiltinValue::kVertexIndex:
+        case builtin::BuiltinValue::kVertexIndex:
             return "vertex_id";
-        case ast::BuiltinValue::kInstanceIndex:
+        case builtin::BuiltinValue::kInstanceIndex:
             return "instance_id";
-        case ast::BuiltinValue::kFrontFacing:
+        case builtin::BuiltinValue::kFrontFacing:
             return "front_facing";
-        case ast::BuiltinValue::kFragDepth:
+        case builtin::BuiltinValue::kFragDepth:
             return "depth(any)";
-        case ast::BuiltinValue::kLocalInvocationId:
+        case builtin::BuiltinValue::kLocalInvocationId:
             return "thread_position_in_threadgroup";
-        case ast::BuiltinValue::kLocalInvocationIndex:
+        case builtin::BuiltinValue::kLocalInvocationIndex:
             return "thread_index_in_threadgroup";
-        case ast::BuiltinValue::kGlobalInvocationId:
+        case builtin::BuiltinValue::kGlobalInvocationId:
             return "thread_position_in_grid";
-        case ast::BuiltinValue::kWorkgroupId:
+        case builtin::BuiltinValue::kWorkgroupId:
             return "threadgroup_position_in_grid";
-        case ast::BuiltinValue::kNumWorkgroups:
+        case builtin::BuiltinValue::kNumWorkgroups:
             return "threadgroups_per_grid";
-        case ast::BuiltinValue::kSampleIndex:
+        case builtin::BuiltinValue::kSampleIndex:
             return "sample_id";
-        case ast::BuiltinValue::kSampleMask:
+        case builtin::BuiltinValue::kSampleMask:
             return "sample_mask";
-        case ast::BuiltinValue::kPointSize:
+        case builtin::BuiltinValue::kPointSize:
             return "point_size";
         default:
             break;
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index f983506..750bed5 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -360,7 +360,7 @@
     /// Converts a builtin to an attribute name
     /// @param builtin the builtin to convert
     /// @returns the string name of the builtin or blank on error
-    std::string builtin_to_attribute(ast::BuiltinValue builtin) const;
+    std::string builtin_to_attribute(builtin::BuiltinValue builtin) const;
 
     /// Converts interpolation attributes to an MSL attribute
     /// @param type the interpolation type
diff --git a/src/tint/writer/msl/generator_impl_binary_test.cc b/src/tint/writer/msl/generator_impl_binary_test.cc
index 4916799..7519b61 100644
--- a/src/tint/writer/msl/generator_impl_binary_test.cc
+++ b/src/tint/writer/msl/generator_impl_binary_test.cc
@@ -155,7 +155,7 @@
 }
 
 TEST_F(MslBinaryTest, ModF16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* left = Var("left", ty.f16());
     auto* right = Var("right", ty.f16());
@@ -183,7 +183,7 @@
 }
 
 TEST_F(MslBinaryTest, ModVec3F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* left = Var("left", ty.vec3<f16>());
     auto* right = Var("right", ty.vec3<f16>());
diff --git a/src/tint/writer/msl/generator_impl_builtin_test.cc b/src/tint/writer/msl/generator_impl_builtin_test.cc
index c0f0ff3..0eabc02 100644
--- a/src/tint/writer/msl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_test.cc
@@ -214,7 +214,7 @@
     auto param = GetParam();
 
     if (param.type == CallParamType::kF16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
 
         GlobalVar("h2", ty.vec2<f16>(), type::AddressSpace::kPrivate);
         GlobalVar("h3", ty.vec3<f16>(), type::AddressSpace::kPrivate);
@@ -436,7 +436,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Runtime_Modf_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("f", Expr(1.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
@@ -498,7 +498,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Runtime_Modf_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("f", vec3<f16>(1.5_h, 2.5_h, 3.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
@@ -552,7 +552,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Const_Modf_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("modf", 1.5_h))));
 
@@ -598,7 +598,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Const_Modf_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("modf", vec3<f16>(1.5_h, 2.5_h, 3.5_h)))));
 
@@ -652,7 +652,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Runtime_Frexp_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Var("f", Expr(1_h)),  //
                    Var("v", Call("frexp", "f")));
@@ -714,7 +714,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Runtime_Frexp_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Var("f", Expr(vec3<f16>())),  //
                    Var("v", Call("frexp", "f")));
@@ -768,7 +768,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Const_Frexp_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("frexp", 1_h))));
 
@@ -814,7 +814,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Const_Frexp_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Decl(Let("v", Call("frexp", vec3<f16>()))));
 
@@ -888,7 +888,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Degrees_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.f16());
     auto* call = Call("degrees", val);
@@ -915,7 +915,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Degrees_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.vec3<f16>());
     auto* call = Call("degrees", val);
@@ -992,7 +992,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Radians_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.f16());
     auto* call = Call("radians", val);
@@ -1019,7 +1019,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Radians_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* val = Var("val", ty.vec3<f16>());
     auto* call = Call("radians", val);
diff --git a/src/tint/writer/msl/generator_impl_function_test.cc b/src/tint/writer/msl/generator_impl_function_test.cc
index a93d262..de88ecb 100644
--- a/src/tint/writer/msl/generator_impl_function_test.cc
+++ b/src/tint/writer/msl/generator_impl_function_test.cc
@@ -136,7 +136,7 @@
     //   return coord.x;
     // }
     auto* coord_in =
-        Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
+        Param("coord", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
     Func("frag_main", utils::Vector{coord_in}, ty.f32(),
          utils::Vector{
              Return(MemberAccessor("coord", "x")),
@@ -145,7 +145,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kFragDepth),
+             Builtin(builtin::BuiltinValue::kFragDepth),
          });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -190,7 +190,7 @@
         utils::Vector{
             Member("col1", ty.f32(), utils::Vector{Location(1_a)}),
             Member("col2", ty.f32(), utils::Vector{Location(2_a)}),
-            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
         });
 
     Func("vert_main", utils::Empty, ty.Of(interface_struct),
@@ -271,7 +271,7 @@
     auto* vertex_output_struct = Structure(
         "VertexOutput",
         utils::Vector{
-            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
         });
 
     Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
diff --git a/src/tint/writer/msl/generator_impl_initializer_test.cc b/src/tint/writer/msl/generator_impl_initializer_test.cc
index bbcadfd..fbd1def 100644
--- a/src/tint/writer/msl/generator_impl_initializer_test.cc
+++ b/src/tint/writer/msl/generator_impl_initializer_test.cc
@@ -62,7 +62,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitInitializer_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
     WrapInFunction(Expr(f16((1 << 15) - 8)));
@@ -83,7 +83,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitInitializer_Type_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Call<f16>(-1.2e-3_h));
 
@@ -130,7 +130,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
 
@@ -150,7 +150,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_Empty_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>());
 
@@ -170,7 +170,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_F16_Literal) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(2_h));
 
@@ -193,7 +193,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Vec_SingleScalar_F16_Var) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
     auto* cast = vec3<f16>(var);
@@ -245,7 +245,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
 
@@ -291,7 +291,7 @@
     //     vec4<f16>(7.0h),
     //     vec4<f16>(vec4<f16>(42.0h, 21.0h, 6.0h, -5.0h)),
     //   );
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vector_literal =
         vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
@@ -325,7 +325,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitInitializer_Type_Mat_Empty_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>());
 
@@ -361,7 +361,7 @@
     //     var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
     // }
 
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
     auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
diff --git a/src/tint/writer/msl/generator_impl_module_constant_test.cc b/src/tint/writer/msl/generator_impl_module_constant_test.cc
index e798364..8a326e2 100644
--- a/src/tint/writer/msl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/msl/generator_impl_module_constant_test.cc
@@ -113,7 +113,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", Expr(1_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
@@ -187,7 +187,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", vec3<f16>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
@@ -243,7 +243,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalConst("G", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
diff --git a/src/tint/writer/msl/generator_impl_test.cc b/src/tint/writer/msl/generator_impl_test.cc
index 7f0e8f5..71d5858 100644
--- a/src/tint/writer/msl/generator_impl_test.cc
+++ b/src/tint/writer/msl/generator_impl_test.cc
@@ -32,7 +32,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, UnsupportedExtension) {
-    Enable(Source{{12, 34}}, ast::Extension::kUndefined);
+    Enable(Source{{12, 34}}, builtin::Extension::kUndefined);
 
     GeneratorImpl& gen = Build();
 
@@ -61,7 +61,7 @@
 }
 
 struct MslBuiltinData {
-    ast::BuiltinValue builtin;
+    builtin::BuiltinValue builtin;
     const char* attribute_name;
 };
 inline std::ostream& operator<<(std::ostream& out, MslBuiltinData data) {
@@ -80,25 +80,25 @@
     MslGeneratorImplTest,
     MslBuiltinConversionTest,
     testing::Values(
-        MslBuiltinData{ast::BuiltinValue::kPosition, "position"},
-        MslBuiltinData{ast::BuiltinValue::kVertexIndex, "vertex_id"},
-        MslBuiltinData{ast::BuiltinValue::kInstanceIndex, "instance_id"},
-        MslBuiltinData{ast::BuiltinValue::kFrontFacing, "front_facing"},
-        MslBuiltinData{ast::BuiltinValue::kFragDepth, "depth(any)"},
-        MslBuiltinData{ast::BuiltinValue::kLocalInvocationId, "thread_position_in_threadgroup"},
-        MslBuiltinData{ast::BuiltinValue::kLocalInvocationIndex, "thread_index_in_threadgroup"},
-        MslBuiltinData{ast::BuiltinValue::kGlobalInvocationId, "thread_position_in_grid"},
-        MslBuiltinData{ast::BuiltinValue::kWorkgroupId, "threadgroup_position_in_grid"},
-        MslBuiltinData{ast::BuiltinValue::kNumWorkgroups, "threadgroups_per_grid"},
-        MslBuiltinData{ast::BuiltinValue::kSampleIndex, "sample_id"},
-        MslBuiltinData{ast::BuiltinValue::kSampleMask, "sample_mask"},
-        MslBuiltinData{ast::BuiltinValue::kPointSize, "point_size"}));
+        MslBuiltinData{builtin::BuiltinValue::kPosition, "position"},
+        MslBuiltinData{builtin::BuiltinValue::kVertexIndex, "vertex_id"},
+        MslBuiltinData{builtin::BuiltinValue::kInstanceIndex, "instance_id"},
+        MslBuiltinData{builtin::BuiltinValue::kFrontFacing, "front_facing"},
+        MslBuiltinData{builtin::BuiltinValue::kFragDepth, "depth(any)"},
+        MslBuiltinData{builtin::BuiltinValue::kLocalInvocationId, "thread_position_in_threadgroup"},
+        MslBuiltinData{builtin::BuiltinValue::kLocalInvocationIndex, "thread_index_in_threadgroup"},
+        MslBuiltinData{builtin::BuiltinValue::kGlobalInvocationId, "thread_position_in_grid"},
+        MslBuiltinData{builtin::BuiltinValue::kWorkgroupId, "threadgroup_position_in_grid"},
+        MslBuiltinData{builtin::BuiltinValue::kNumWorkgroups, "threadgroups_per_grid"},
+        MslBuiltinData{builtin::BuiltinValue::kSampleIndex, "sample_id"},
+        MslBuiltinData{builtin::BuiltinValue::kSampleMask, "sample_mask"},
+        MslBuiltinData{builtin::BuiltinValue::kPointSize, "point_size"}));
 
 TEST_F(MslGeneratorImplTest, HasInvariantAttribute_True) {
     auto* out = Structure("Out", utils::Vector{
                                      Member("pos", ty.vec4<f32>(),
                                             utils::Vector{
-                                                Builtin(ast::BuiltinValue::kPosition),
+                                                Builtin(builtin::BuiltinValue::kPosition),
                                                 Invariant(),
                                             }),
                                  });
@@ -136,7 +136,7 @@
     auto* out = Structure("Out", utils::Vector{
                                      Member("pos", ty.vec4<f32>(),
                                             utils::Vector{
-                                                Builtin(ast::BuiltinValue::kPosition),
+                                                Builtin(builtin::BuiltinValue::kPosition),
                                             }),
                                  });
     Func("vert_main", utils::Empty, ty.Of(out), utils::Vector{Return(Call(ty.Of(out)))},
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 927ae26..1386abb 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
@@ -155,7 +155,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", Expr(1_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
@@ -229,7 +229,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", vec3<f16>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
@@ -285,7 +285,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
@@ -415,7 +415,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("a", ty.vec2<f16>());
     auto* stmt = Decl(var);
@@ -444,7 +444,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Matrix_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("a", ty.mat3x2<f16>());
 
@@ -473,7 +473,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroVec_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("a", ty.vec3<f16>(), vec3<f16>());
 
@@ -502,7 +502,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroMat_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("a", ty.mat2x3<f16>(), mat2x3<f16>());
 
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 008cf41..7482558 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -265,11 +265,11 @@
 bool Builder::Build() {
     if (!CheckSupportedExtensions("SPIR-V", builder_.AST(), builder_.Diagnostics(),
                                   utils::Vector{
-                                      ast::Extension::kChromiumDisableUniformityAnalysis,
-                                      ast::Extension::kChromiumExperimentalDp4A,
-                                      ast::Extension::kChromiumExperimentalFullPtrParameters,
-                                      ast::Extension::kChromiumExperimentalPushConstant,
-                                      ast::Extension::kF16,
+                                      builtin::Extension::kChromiumDisableUniformityAnalysis,
+                                      builtin::Extension::kChromiumExperimentalDp4A,
+                                      builtin::Extension::kChromiumExperimentalFullPtrParameters,
+                                      builtin::Extension::kChromiumExperimentalPushConstant,
+                                      builtin::Extension::kF16,
                                   })) {
         error_ = builder_.Diagnostics().str();
         return false;
@@ -394,14 +394,14 @@
     extensions_.push_back(Instruction{spv::Op::OpExtension, {Operand(extension)}});
 }
 
-bool Builder::GenerateExtension(ast::Extension extension) {
+bool Builder::GenerateExtension(builtin::Extension extension) {
     switch (extension) {
-        case ast::Extension::kChromiumExperimentalDp4A:
+        case builtin::Extension::kChromiumExperimentalDp4A:
             push_extension("SPV_KHR_integer_dot_product");
             push_capability(SpvCapabilityDotProductKHR);
             push_capability(SpvCapabilityDotProductInput4x8BitPackedKHR);
             break;
-        case ast::Extension::kF16:
+        case builtin::Extension::kF16:
             push_capability(SpvCapabilityFloat16);
             push_capability(SpvCapabilityUniformAndStorageBuffer16BitAccess);
             push_capability(SpvCapabilityStorageBuffer16BitAccess);
@@ -549,7 +549,7 @@
     }
 
     for (auto builtin : func_sem->TransitivelyReferencedBuiltinVariables()) {
-        if (builtin.second->builtin == ast::BuiltinValue::kFragDepth) {
+        if (builtin.second->builtin == builtin::BuiltinValue::kFragDepth) {
             push_execution_mode(spv::Op::OpExecutionMode,
                                 {Operand(id), U32Operand(SpvExecutionModeDepthReplacing)});
         }
@@ -4004,9 +4004,9 @@
     return SpvStorageClassMax;
 }
 
-SpvBuiltIn Builder::ConvertBuiltin(ast::BuiltinValue builtin, type::AddressSpace storage) {
+SpvBuiltIn Builder::ConvertBuiltin(builtin::BuiltinValue builtin, type::AddressSpace storage) {
     switch (builtin) {
-        case ast::BuiltinValue::kPosition:
+        case builtin::BuiltinValue::kPosition:
             if (storage == type::AddressSpace::kIn) {
                 return SpvBuiltInFragCoord;
             } else if (TINT_LIKELY(storage == type::AddressSpace::kOut)) {
@@ -4015,32 +4015,32 @@
                 TINT_ICE(Writer, builder_.Diagnostics()) << "invalid address space for builtin";
                 break;
             }
-        case ast::BuiltinValue::kVertexIndex:
+        case builtin::BuiltinValue::kVertexIndex:
             return SpvBuiltInVertexIndex;
-        case ast::BuiltinValue::kInstanceIndex:
+        case builtin::BuiltinValue::kInstanceIndex:
             return SpvBuiltInInstanceIndex;
-        case ast::BuiltinValue::kFrontFacing:
+        case builtin::BuiltinValue::kFrontFacing:
             return SpvBuiltInFrontFacing;
-        case ast::BuiltinValue::kFragDepth:
+        case builtin::BuiltinValue::kFragDepth:
             return SpvBuiltInFragDepth;
-        case ast::BuiltinValue::kLocalInvocationId:
+        case builtin::BuiltinValue::kLocalInvocationId:
             return SpvBuiltInLocalInvocationId;
-        case ast::BuiltinValue::kLocalInvocationIndex:
+        case builtin::BuiltinValue::kLocalInvocationIndex:
             return SpvBuiltInLocalInvocationIndex;
-        case ast::BuiltinValue::kGlobalInvocationId:
+        case builtin::BuiltinValue::kGlobalInvocationId:
             return SpvBuiltInGlobalInvocationId;
-        case ast::BuiltinValue::kPointSize:
+        case builtin::BuiltinValue::kPointSize:
             return SpvBuiltInPointSize;
-        case ast::BuiltinValue::kWorkgroupId:
+        case builtin::BuiltinValue::kWorkgroupId:
             return SpvBuiltInWorkgroupId;
-        case ast::BuiltinValue::kNumWorkgroups:
+        case builtin::BuiltinValue::kNumWorkgroups:
             return SpvBuiltInNumWorkgroups;
-        case ast::BuiltinValue::kSampleIndex:
+        case builtin::BuiltinValue::kSampleIndex:
             push_capability(SpvCapabilitySampleRateShading);
             return SpvBuiltInSampleId;
-        case ast::BuiltinValue::kSampleMask:
+        case builtin::BuiltinValue::kSampleMask:
             return SpvBuiltInSampleMask;
-        case ast::BuiltinValue::kUndefined:
+        case builtin::BuiltinValue::kUndefined:
             break;
     }
     return SpvBuiltInMax;
diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h
index 6f9bf5d..c56085a 100644
--- a/src/tint/writer/spirv/builder.h
+++ b/src/tint/writer/spirv/builder.h
@@ -213,7 +213,7 @@
     /// @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(ast::BuiltinValue builtin, type::AddressSpace storage);
+    SpvBuiltIn ConvertBuiltin(builtin::BuiltinValue builtin, type::AddressSpace storage);
 
     /// Converts an interpolate attribute to SPIR-V decorations and pushes a
     /// capability if needed.
@@ -228,7 +228,7 @@
     /// not supported.
     /// @param ext the extension to generate
     /// @returns true on success.
-    bool GenerateExtension(ast::Extension ext);
+    bool GenerateExtension(builtin::Extension ext);
     /// Generates a label for the given id. Emits an error and returns false if
     /// we're currently outside a function.
     /// @param id the id to use for the label
diff --git a/src/tint/writer/spirv/builder_binary_expression_test.cc b/src/tint/writer/spirv/builder_binary_expression_test.cc
index ed8185d..b6dfb62 100644
--- a/src/tint/writer/spirv/builder_binary_expression_test.cc
+++ b/src/tint/writer/spirv/builder_binary_expression_test.cc
@@ -248,7 +248,7 @@
 
 using BinaryArithF16Test = TestParamHelper<BinaryData>;
 TEST_P(BinaryArithF16Test, Scalar) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
 
@@ -273,7 +273,7 @@
 }
 
 TEST_P(BinaryArithF16Test, Vector) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
 
@@ -543,7 +543,7 @@
 
 using BinaryCompareF16Test = TestParamHelper<BinaryData>;
 TEST_P(BinaryCompareF16Test, Scalar) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
 
@@ -569,7 +569,7 @@
 }
 
 TEST_P(BinaryCompareF16Test, Vector) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
 
@@ -629,7 +629,7 @@
 }
 
 TEST_F(BuilderTest, Binary_Multiply_VectorScalar_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
     auto* rhs = Expr(1_h);
@@ -677,7 +677,7 @@
 }
 
 TEST_F(BuilderTest, Binary_Multiply_ScalarVector_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* lhs = Expr(1_h);
     auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
@@ -728,7 +728,7 @@
 }
 
 TEST_F(BuilderTest, Binary_Multiply_MatrixScalar_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("mat", ty.mat3x3<f16>());
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), Expr(1_h));
@@ -782,7 +782,7 @@
 }
 
 TEST_F(BuilderTest, Binary_Multiply_ScalarMatrix_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("mat", ty.mat3x3<f16>());
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr(1_h), Expr("mat"));
@@ -838,7 +838,7 @@
 }
 
 TEST_F(BuilderTest, Binary_Multiply_MatrixVector_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("mat", ty.mat3x3<f16>());
     auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
@@ -896,7 +896,7 @@
 }
 
 TEST_F(BuilderTest, Binary_Multiply_VectorMatrix_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("mat", ty.mat3x3<f16>());
     auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
@@ -953,7 +953,7 @@
 }
 
 TEST_F(BuilderTest, Binary_Multiply_MatrixMatrix_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Var("mat", ty.mat3x3<f16>());
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), Expr("mat"));
@@ -1341,7 +1341,7 @@
     auto& param = GetParam();
 
     if (param.type == Type::f16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
     }
 
     const ast::Expression* lhs = MakeVectorExpr(this, param.type);
@@ -1393,7 +1393,7 @@
     auto& param = GetParam();
 
     if (param.type == Type::f16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
     }
 
     const ast::Expression* lhs = MakeScalarExpr(this, param.type);
@@ -1473,7 +1473,7 @@
     auto& param = GetParam();
 
     if (param.type == Type::f16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
     }
 
     const ast::Expression* lhs = MakeVectorExpr(this, param.type);
@@ -1521,7 +1521,7 @@
     auto& param = GetParam();
 
     if (param.type == Type::f16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
     }
 
     const ast::Expression* lhs = MakeScalarExpr(this, param.type);
@@ -1636,7 +1636,7 @@
     auto& param = GetParam();
 
     if (param.type == Type::f16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
     }
 
     const ast::Expression* lhs = MakeMat3x4Expr(this, param.type);
@@ -1699,7 +1699,7 @@
     auto& param = GetParam();
 
     if (param.type == Type::f16) {
-        Enable(ast::Extension::kF16);
+        Enable(builtin::Extension::kF16);
     }
 
     const ast::Expression* lhs = MakeMat3x4Expr(this, param.type);
diff --git a/src/tint/writer/spirv/builder_builtin_test.cc b/src/tint/writer/spirv/builder_builtin_test.cc
index 0bab161..693fdb1 100644
--- a/src/tint/writer/spirv/builder_builtin_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_test.cc
@@ -132,7 +132,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("ident", ty.f16(), type::AddressSpace::kPrivate);
     auto* expr = Call("round", "ident");
@@ -516,7 +516,7 @@
 }
 
 TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
     // Use a variable to prevent the function being evaluated as constant.
@@ -599,7 +599,7 @@
 }
 
 TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
 
@@ -705,7 +705,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Length_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* scalar = Var("a", Expr(1_h));
     auto* expr = Call("length", scalar);
@@ -779,7 +779,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Length_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec = Var("a", vec2<f16>(1_h, 1_h));
     auto* expr = Call("length", vec);
@@ -855,7 +855,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Normalize_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec = Var("a", vec2<f16>(1_h, 1_h));
     auto* expr = Call("normalize", vec);
@@ -934,7 +934,7 @@
 }
 
 TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
     auto* scalar = Var("scalar", Expr(1_h));
@@ -1016,7 +1016,7 @@
 }
 
 TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
     auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
@@ -1105,7 +1105,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Reflect_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
     auto* expr = Call("reflect", vec, vec);
@@ -1181,7 +1181,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Distance_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* scalar = Var("scalar", Expr(1_h));
     auto* expr = Call("distance", scalar, scalar);
@@ -1257,7 +1257,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Distance_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
     auto* expr = Call("distance", vec, vec);
@@ -1335,7 +1335,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Cross_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec = Var("vec", vec3<f16>(1_h, 1_h, 1_h));
     auto* expr = Call("cross", vec, vec);
@@ -1416,7 +1416,7 @@
 }
 
 TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Scalar_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
     auto* scalar = Var("scalar", Expr(1_h));
@@ -1500,7 +1500,7 @@
 }
 
 TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
     auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
@@ -1591,7 +1591,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
     auto* expr = Call("faceForward", vec, vec, vec);
@@ -1684,7 +1684,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Runtime_Call_Modf_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec = Var("vec", vec2<f16>(1_h, 2_h));
     auto* expr = Call("modf", vec);
@@ -1786,7 +1786,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Const_Call_Modf_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* expr = Call("modf", vec2<f16>(1_h, 2_h));
     Func("a_func", utils::Empty, ty.void_(),
@@ -1890,7 +1890,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Runtime_Call_Frexp_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* vec = Var("vec", vec2<f16>(1_h, 2_h));
     auto* expr = Call("frexp", vec);
@@ -1995,7 +1995,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Const_Call_Frexp_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -3149,7 +3149,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Determinant_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("var", ty.mat3x3<f16>(), type::AddressSpace::kPrivate);
     auto* expr = Call("determinant", "var");
@@ -3222,7 +3222,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Transpose_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("var", ty.mat2x3<f16>(), type::AddressSpace::kPrivate);
     auto* expr = Call("transpose", "var");
@@ -3294,7 +3294,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Dot_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("v", ty.vec3<f16>(), type::AddressSpace::kPrivate);
     auto* expr = Call("dot", "v", "v");
@@ -4153,7 +4153,7 @@
 TEST_F(BuiltinBuilderTest, Call_Dot4I8Packed) {
     auto* ext =
         create<ast::Enable>(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}},
-                            ast::Extension::kChromiumExperimentalDp4A);
+                            builtin::Extension::kChromiumExperimentalDp4A);
     AST().AddEnable(ext);
 
     auto* val1 = Var("val1", ty.u32());
@@ -4193,7 +4193,7 @@
 TEST_F(BuiltinBuilderTest, Call_Dot4U8Packed) {
     auto* ext =
         create<ast::Enable>(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}},
-                            ast::Extension::kChromiumExperimentalDp4A);
+                            builtin::Extension::kChromiumExperimentalDp4A);
     AST().AddEnable(ext);
 
     auto* val1 = Var("val1", ty.u32());
diff --git a/src/tint/writer/spirv/builder_entry_point_test.cc b/src/tint/writer/spirv/builder_entry_point_test.cc
index 7b55804..59e1848 100644
--- a/src/tint/writer/spirv/builder_entry_point_test.cc
+++ b/src/tint/writer/spirv/builder_entry_point_test.cc
@@ -16,11 +16,11 @@
 
 #include "gtest/gtest.h"
 #include "src/tint/ast/builtin_attribute.h"
-#include "src/tint/ast/builtin_value.h"
 #include "src/tint/ast/location_attribute.h"
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/variable.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"
@@ -44,7 +44,7 @@
     // }
     auto* coord = Param("coord", ty.vec4<f32>(),
                         utils::Vector{
-                            Builtin(ast::BuiltinValue::kPosition),
+                            Builtin(builtin::BuiltinValue::kPosition),
                         });
     auto* loc1 = Param("loc1", ty.f32(),
                        utils::Vector{
@@ -212,7 +212,7 @@
         "Interface",
         utils::Vector{
             Member("value", ty.f32(), utils::Vector{Location(1_u)}),
-            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(ast::BuiltinValue::kPosition)}),
+            Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
         });
 
     auto* vert_retval = Call(ty.Of(interface), 42_f, vec4<f32>());
@@ -228,7 +228,7 @@
          },
          utils::Vector{Stage(ast::PipelineStage::kFragment)},
          utils::Vector{
-             Builtin(ast::BuiltinValue::kFragDepth),
+             Builtin(builtin::BuiltinValue::kFragDepth),
          });
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -322,7 +322,7 @@
 TEST_F(BuilderTest, SampleIndex_SampleRateShadingCapability) {
     Func("main",
          utils::Vector{Param("sample_index", ty.u32(),
-                             utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)})},
+                             utils::Vector{Builtin(builtin::BuiltinValue::kSampleIndex)})},
          ty.void_(), utils::Empty,
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
diff --git a/src/tint/writer/spirv/builder_function_attribute_test.cc b/src/tint/writer/spirv/builder_function_attribute_test.cc
index 8776842..555c9ea 100644
--- a/src/tint/writer/spirv/builder_function_attribute_test.cc
+++ b/src/tint/writer/spirv/builder_function_attribute_test.cc
@@ -56,7 +56,7 @@
     utils::Vector<const ast::Statement*, 2> body;
     if (params.stage == ast::PipelineStage::kVertex) {
         ret_type = ty.vec4<f32>();
-        ret_type_attrs.Push(Builtin(ast::BuiltinValue::kPosition));
+        ret_type_attrs.Push(Builtin(builtin::BuiltinValue::kPosition));
         body.Push(Return(Call(ty.vec4<f32>())));
     }
 
@@ -226,7 +226,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          utils::Vector{
-             Builtin(ast::BuiltinValue::kFragDepth),
+             Builtin(builtin::BuiltinValue::kFragDepth),
          });
 
     spirv::Builder& b = SanitizeAndBuild();
diff --git a/src/tint/writer/spirv/builder_global_variable_test.cc b/src/tint/writer/spirv/builder_global_variable_test.cc
index a246cbd..ea9c6a8 100644
--- a/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -119,7 +119,7 @@
 TEST_F(BuilderTest, GlobalConst_Vec_F16_Initializer) {
     // const c = vec3<f16>(1h, 2h, 3h);
     // var v = c;
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* c = GlobalConst("c", vec3<f16>(1_h, 2_h, 3_h));
     GlobalVar("v", type::AddressSpace::kPrivate, Expr(c));
@@ -251,7 +251,7 @@
 }
 
 struct BuiltinData {
-    ast::BuiltinValue builtin;
+    builtin::BuiltinValue builtin;
     type::AddressSpace storage;
     SpvBuiltIn result;
 };
@@ -271,32 +271,35 @@
     BuilderTest_Type,
     BuiltinDataTest,
     testing::Values(
-        BuiltinData{ast::BuiltinValue::kUndefined, type::AddressSpace::kNone, SpvBuiltInMax},
-        BuiltinData{ast::BuiltinValue::kPosition, type::AddressSpace::kIn, SpvBuiltInFragCoord},
-        BuiltinData{ast::BuiltinValue::kPosition, type::AddressSpace::kOut, SpvBuiltInPosition},
+        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{
-            ast::BuiltinValue::kVertexIndex,
+            builtin::BuiltinValue::kVertexIndex,
             type::AddressSpace::kIn,
             SpvBuiltInVertexIndex,
         },
-        BuiltinData{ast::BuiltinValue::kInstanceIndex, type::AddressSpace::kIn,
+        BuiltinData{builtin::BuiltinValue::kInstanceIndex, type::AddressSpace::kIn,
                     SpvBuiltInInstanceIndex},
-        BuiltinData{ast::BuiltinValue::kFrontFacing, type::AddressSpace::kIn,
+        BuiltinData{builtin::BuiltinValue::kFrontFacing, type::AddressSpace::kIn,
                     SpvBuiltInFrontFacing},
-        BuiltinData{ast::BuiltinValue::kFragDepth, type::AddressSpace::kOut, SpvBuiltInFragDepth},
-        BuiltinData{ast::BuiltinValue::kLocalInvocationId, type::AddressSpace::kIn,
+        BuiltinData{builtin::BuiltinValue::kFragDepth, type::AddressSpace::kOut,
+                    SpvBuiltInFragDepth},
+        BuiltinData{builtin::BuiltinValue::kLocalInvocationId, type::AddressSpace::kIn,
                     SpvBuiltInLocalInvocationId},
-        BuiltinData{ast::BuiltinValue::kLocalInvocationIndex, type::AddressSpace::kIn,
+        BuiltinData{builtin::BuiltinValue::kLocalInvocationIndex, type::AddressSpace::kIn,
                     SpvBuiltInLocalInvocationIndex},
-        BuiltinData{ast::BuiltinValue::kGlobalInvocationId, type::AddressSpace::kIn,
+        BuiltinData{builtin::BuiltinValue::kGlobalInvocationId, type::AddressSpace::kIn,
                     SpvBuiltInGlobalInvocationId},
-        BuiltinData{ast::BuiltinValue::kWorkgroupId, type::AddressSpace::kIn,
+        BuiltinData{builtin::BuiltinValue::kWorkgroupId, type::AddressSpace::kIn,
                     SpvBuiltInWorkgroupId},
-        BuiltinData{ast::BuiltinValue::kNumWorkgroups, type::AddressSpace::kIn,
+        BuiltinData{builtin::BuiltinValue::kNumWorkgroups, type::AddressSpace::kIn,
                     SpvBuiltInNumWorkgroups},
-        BuiltinData{ast::BuiltinValue::kSampleIndex, type::AddressSpace::kIn, SpvBuiltInSampleId},
-        BuiltinData{ast::BuiltinValue::kSampleMask, type::AddressSpace::kIn, SpvBuiltInSampleMask},
-        BuiltinData{ast::BuiltinValue::kSampleMask, type::AddressSpace::kOut,
+        BuiltinData{builtin::BuiltinValue::kSampleIndex, type::AddressSpace::kIn,
+                    SpvBuiltInSampleId},
+        BuiltinData{builtin::BuiltinValue::kSampleMask, type::AddressSpace::kIn,
+                    SpvBuiltInSampleMask},
+        BuiltinData{builtin::BuiltinValue::kSampleMask, type::AddressSpace::kOut,
                     SpvBuiltInSampleMask}));
 
 TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
diff --git a/src/tint/writer/spirv/builder_initializer_expression_test.cc b/src/tint/writer/spirv/builder_initializer_expression_test.cc
index b78bd9d..9fdc4fc 100644
--- a/src/tint/writer/spirv/builder_initializer_expression_test.cc
+++ b/src/tint/writer/spirv/builder_initializer_expression_test.cc
@@ -213,7 +213,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_F16_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = Call<f16>(2_h);
     WrapInFunction(cast);
@@ -288,7 +288,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F16_Literal) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(2_h);
     WrapInFunction(cast);
@@ -332,7 +332,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F16_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
     auto* cast = vec2<f16>("x", "x");
@@ -377,7 +377,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec2_With_F16_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(1_h, 2_h);
     WrapInFunction(cast);
@@ -422,7 +422,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec2_F16_With_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
     auto* cast = vec2<f16>("x");
@@ -467,7 +467,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec2_F16_With_Vec2_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(vec2<f16>(1_h, 2_h));
     WrapInFunction(cast);
@@ -513,7 +513,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
     auto* cast = vec3<f16>("x", "x", "x");
@@ -560,7 +560,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(1_h, 2_h, 3_h);
     WrapInFunction(cast);
@@ -651,7 +651,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_F16_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
     auto* cast = vec3<f16>("x", "x", "x");
@@ -698,7 +698,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_F16_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(1_h, 2_h, 3_h);
     WrapInFunction(cast);
@@ -749,7 +749,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
     auto* cast = vec3<f16>(1_h, "x");
@@ -800,7 +800,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_F16_Vec2_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(1_h, vec2<f16>(2_h, 3_h));
     WrapInFunction(cast);
@@ -851,7 +851,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_Vec2_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
     auto* cast = vec3<f16>("x", 3_h);
@@ -902,7 +902,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_With_Vec2_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec2<f16>(1_h, 2_h), 3_h);
     WrapInFunction(cast);
@@ -949,7 +949,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_F16_With_Vec3) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(1_h, 2_h, 3_h)));
     auto* cast = vec3<f16>("x");
@@ -996,7 +996,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec3_F16_With_Vec3_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec3<f16>(1_h, 2_h, 3_h));
     WrapInFunction(cast);
@@ -1082,7 +1082,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
     auto* cast = vec4<f16>("x");
@@ -1125,7 +1125,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h);
     WrapInFunction(cast);
@@ -1171,7 +1171,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_F16_F16_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
     auto* cast = vec4<f16>("x", "x", "x", "x");
@@ -1220,7 +1220,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_F16_F16_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(1_h, 2_h, 3_h, 4_h);
     WrapInFunction(cast);
@@ -1271,7 +1271,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_F16_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
     auto* cast = vec4<f16>(1_h, 2_h, "x");
@@ -1322,7 +1322,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_F16_Vec2_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(1_h, 2_h, vec2<f16>(3_h, 4_h));
     WrapInFunction(cast);
@@ -1375,7 +1375,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Vec2_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
     auto* cast = vec4<f16>(1_h, "x", 4_h);
@@ -1428,7 +1428,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Vec2_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(1_h, vec2<f16>(2_h, 3_h), 4_h);
     WrapInFunction(cast);
@@ -1481,7 +1481,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec2_F16_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
     auto* cast = vec4<f16>("x", 3_h, 4_h);
@@ -1534,7 +1534,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec2_F16_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), 3_h, 4_h);
     WrapInFunction(cast);
@@ -1588,7 +1588,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_F16_With_Vec2_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
     auto* cast = vec4<f16>("x", "x");
@@ -1640,7 +1640,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_F16_With_Vec2_Vec2_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), vec2<f16>(1_h, 2_h));
     WrapInFunction(cast);
@@ -1689,7 +1689,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Vec3) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
     auto* cast = vec4<f16>(2_h, "x");
@@ -1737,7 +1737,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_F16_Vec3_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
     WrapInFunction(cast);
@@ -1785,7 +1785,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec3_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
     auto* cast = vec4<f16>("x", 2_h);
@@ -1833,7 +1833,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_With_Vec3_F16_Const) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
     WrapInFunction(cast);
@@ -1870,7 +1870,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Vec4_F16_With_Vec4) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* value = vec4<f16>(2_h, 2_h, 2_h, 2_h);
     auto* cast = vec4<f16>(value);
@@ -1911,7 +1911,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_F16_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* ctor = Call<f16>(2_h);
     GlobalConst("g", ty.f16(), ctor);
@@ -1951,7 +1951,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_F16_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* ctor = Call<f16>(2_h);
     GlobalVar("g", ty.f16(), type::AddressSpace::kPrivate, ctor);
@@ -1991,7 +1991,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_U32_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* ctor = Call<u32>(1.5_h);
     GlobalConst("g", ty.u32(), ctor);
@@ -2031,7 +2031,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_U32_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* ctor = Call<u32>(1.5_h);
     GlobalVar("g", ty.u32(), type::AddressSpace::kPrivate, ctor);
@@ -2073,7 +2073,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec2_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(2_h);
     GlobalConst("g", ty.vec2<f16>(), cast);
@@ -2114,7 +2114,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec2_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(2_h);
     auto* g = GlobalVar("g", ty.vec2<f16>(), type::AddressSpace::kPrivate, cast);
@@ -2155,7 +2155,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec2_F16_With_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
     GlobalConst("g", ty.vec2<f16>(), cast);
@@ -2200,7 +2200,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec2_F16_With_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
     GlobalVar("a", ty.vec2<f16>(), type::AddressSpace::kPrivate, cast);
@@ -2245,7 +2245,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_F16_With_Vec3) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
     GlobalConst("g", ty.vec3<f16>(), cast);
@@ -2290,7 +2290,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_F16_With_Vec3) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -2335,7 +2335,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_F16_With_Vec4) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
     GlobalConst("g", ty.vec4<f16>(), cast);
@@ -2380,7 +2380,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_F16_With_Vec4) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -2425,7 +2425,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(2_h);
     GlobalConst("g", ty.vec3<f16>(), cast);
@@ -2466,7 +2466,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(2_h);
     auto* g = GlobalVar("g", ty.vec3<f16>(), type::AddressSpace::kPrivate, cast);
@@ -2507,7 +2507,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_F16_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
     GlobalConst("g", ty.vec3<f16>(), cast);
@@ -2548,7 +2548,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_F16_Vec2) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -2589,7 +2589,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec3_With_Vec2_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
     GlobalConst("g", ty.vec3<f16>(), cast);
@@ -2630,7 +2630,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec3_With_Vec2_F16) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -2671,7 +2671,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h);
     GlobalConst("g", ty.vec4<f16>(), cast);
@@ -2712,7 +2712,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h);
     auto* g = GlobalVar("g", ty.vec4<f16>(), type::AddressSpace::kPrivate, cast);
@@ -2753,7 +2753,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F16_F16_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
     GlobalConst("g", ty.vec4<f16>(), cast);
@@ -2794,7 +2794,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F16_F16_Vec2) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -2835,7 +2835,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_F16_Vec2_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
     GlobalConst("g", ty.vec4<f16>(), cast);
@@ -2876,7 +2876,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F16_Vec2_F16) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -2917,7 +2917,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_Vec2_F16_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
     GlobalConst("g", ty.vec4<f16>(), cast);
@@ -2958,7 +2958,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_Vec2_F16_F16) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -2999,7 +2999,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_F16_With_Vec2_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
     GlobalConst("g", ty.vec4<f16>(), cast);
@@ -3040,7 +3040,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_F16_With_Vec2_Vec2) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -3097,7 +3097,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_F16_Vec3) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -3138,7 +3138,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalConst_Vec4_With_Vec3_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
     GlobalConst("g", ty.vec4<f16>(), cast);
@@ -3179,7 +3179,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_GlobalVar_Vec4_With_Vec3_F16) {
-    Enable(ast::Extension::kF16);
+    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);
@@ -3215,7 +3215,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat2x2_F16_With_Vec2_Vec2) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = mat2x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
     WrapInFunction(cast);
@@ -3253,7 +3253,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat3x2_F16_With_Vec2_Vec2_Vec2) {
-    Enable(ast::Extension::kF16);
+    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));
     WrapInFunction(cast);
@@ -3292,7 +3292,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat4x2_F16_With_Vec2_Vec2_Vec2_Vec2) {
-    Enable(ast::Extension::kF16);
+    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),
                              vec2<f16>(2_h, 2_h));
@@ -3331,7 +3331,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat2x3_F16_With_Vec3_Vec3) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = mat2x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
     WrapInFunction(cast);
@@ -3370,7 +3370,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat3x3_F16_With_Vec3_Vec3_Vec3) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast =
         mat3x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
@@ -3410,7 +3410,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat4x3_F16_With_Vec3_Vec3_Vec3_Vec3) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = mat4x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h),
                              vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
@@ -3449,7 +3449,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat2x4_F16_With_Vec4_Vec4) {
-    Enable(ast::Extension::kF16);
+    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));
     WrapInFunction(cast);
@@ -3488,7 +3488,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat3x4_F16_With_Vec4_Vec4_Vec4) {
-    Enable(ast::Extension::kF16);
+    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),
                              vec4<f16>(2_h, 2_h, 2_h, 2_h));
@@ -3528,7 +3528,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Mat4x4_F16_With_Vec4_Vec4_Vec4_Vec4) {
-    Enable(ast::Extension::kF16);
+    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),
                              vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h));
@@ -3567,7 +3567,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Array_5_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = array<f16, 5>(2_h, 2_h, 2_h, 2_h, 2_h);
     WrapInFunction(cast);
@@ -3609,7 +3609,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Array_2_Vec3_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* first = vec3<f16>(1_h, 2_h, 3_h);
     auto* second = vec3<f16>(1_h, 2_h, 3_h);
@@ -3738,7 +3738,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* t = Call<f16>();
 
@@ -3845,7 +3845,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_ZeroInit_Matrix_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* t = mat4x2<f16>();
 
@@ -3952,7 +3952,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_F16_To_I32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2.4_h)));
     auto* cast = Call<i32>("x");
@@ -4026,7 +4026,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_F16_To_U32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2.4_h)));
     auto* cast = Call<u32>("x");
@@ -4100,7 +4100,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_F16_To_F32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
     auto* cast = Call<f32>("x");
@@ -4126,7 +4126,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_I32_To_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.i32(), Expr(2_i)));
     auto* cast = Call<f16>("x");
@@ -4152,7 +4152,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_U32_To_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.u32(), Expr(2_u)));
     auto* cast = Call<f16>("x");
@@ -4178,7 +4178,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_F32_To_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
     auto* cast = Call<f16>("x");
@@ -4256,7 +4256,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F16_to_I32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("i", ty.vec3<f16>(), type::AddressSpace::kPrivate);
 
@@ -4336,7 +4336,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F16_to_U32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("i", ty.vec3<f16>(), type::AddressSpace::kPrivate);
 
@@ -4416,7 +4416,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F16_to_F32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("i", ty.vec3<f16>(), type::AddressSpace::kPrivate);
 
@@ -4444,7 +4444,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_I32_to_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("i", ty.vec3<i32>(), type::AddressSpace::kPrivate);
 
@@ -4472,7 +4472,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_U32_to_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("i", ty.vec3<u32>(), type::AddressSpace::kPrivate);
 
@@ -4500,7 +4500,7 @@
 }
 
 TEST_F(SpvBuilderInitializerTest, Type_Convert_Vectors_F32_to_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* var = GlobalVar("i", ty.vec3<f32>(), type::AddressSpace::kPrivate);
 
diff --git a/src/tint/writer/spirv/builder_literal_test.cc b/src/tint/writer/spirv/builder_literal_test.cc
index 0d53237..3a9ec29 100644
--- a/src/tint/writer/spirv/builder_literal_test.cc
+++ b/src/tint/writer/spirv/builder_literal_test.cc
@@ -164,7 +164,7 @@
 }
 
 TEST_F(BuilderTest, Literal_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* i = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
     WrapInFunction(i);
@@ -181,7 +181,7 @@
 }
 
 TEST_F(BuilderTest, Literal_F16_Dedup) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* i1 = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
     auto* i2 = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
diff --git a/src/tint/writer/spirv/builder_test.cc b/src/tint/writer/spirv/builder_test.cc
index b3dce7e..1c79988 100644
--- a/src/tint/writer/spirv/builder_test.cc
+++ b/src/tint/writer/spirv/builder_test.cc
@@ -30,7 +30,7 @@
 }
 
 TEST_F(BuilderTest, UnsupportedExtension) {
-    Enable(Source{{12, 34}}, ast::Extension::kUndefined);
+    Enable(Source{{12, 34}}, builtin::Extension::kUndefined);
 
     auto program = std::make_unique<Program>(std::move(*this));
     auto result = Generate(program.get(), Options{});
diff --git a/src/tint/writer/spirv/builder_type_test.cc b/src/tint/writer/spirv/builder_type_test.cc
index ad13e96..cf35662 100644
--- a/src/tint/writer/spirv/builder_type_test.cc
+++ b/src/tint/writer/spirv/builder_type_test.cc
@@ -320,7 +320,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* s = Structure("my_struct", utils::Vector{Member("a", ty.f32()), Member("b", ty.f16())});
 
@@ -341,7 +341,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* s = Structure("S", utils::Vector{
                                  Member("a", ty.f32()),
@@ -374,7 +374,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_Matrix) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* s =
         Structure("S", utils::Vector{
@@ -438,7 +438,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_ArraysOfMatrix) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto arr_mat2x2_f32 = ty.array(ty.mat2x2<f32>(), 1_u);  // Singly nested array
     auto arr_mat2x2_f16 = ty.array(ty.mat2x2<f16>(), 1_u);  // Singly nested array
diff --git a/src/tint/writer/wgsl/generator_impl_cast_test.cc b/src/tint/writer/wgsl/generator_impl_cast_test.cc
index b10fd8f..66b7a2e 100644
--- a/src/tint/writer/wgsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_cast_test.cc
@@ -33,7 +33,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar_F16_From_I32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = Call<f16>(1_i);
     WrapInFunction(cast);
@@ -57,7 +57,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector_F16_From_I32) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* cast = vec3<f16>(vec3<i32>(1_i, 2_i, 3_i));
     WrapInFunction(cast);
diff --git a/src/tint/writer/wgsl/generator_impl_enable_test.cc b/src/tint/writer/wgsl/generator_impl_enable_test.cc
index 503a9a0..739d893 100644
--- a/src/tint/writer/wgsl/generator_impl_enable_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_enable_test.cc
@@ -20,7 +20,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Enable) {
-    auto* enable = Enable(ast::Extension::kF16);
+    auto* enable = Enable(builtin::Extension::kF16);
 
     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 42e0184..34e26b4 100644
--- a/src/tint/writer/wgsl/generator_impl_function_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_function_test.cc
@@ -112,7 +112,7 @@
     auto vec4 = ty.vec4<f32>();
     auto* coord = Param("coord", vec4,
                         utils::Vector{
-                            Builtin(ast::BuiltinValue::kPosition),
+                            Builtin(builtin::BuiltinValue::kPosition),
                         });
     auto* loc1 = Param("loc1", ty.f32(),
                        utils::Vector{
diff --git a/src/tint/writer/wgsl/generator_impl_initializer_test.cc b/src/tint/writer/wgsl/generator_impl_initializer_test.cc
index 87dddca..0d5686e 100644
--- a/src/tint/writer/wgsl/generator_impl_initializer_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_initializer_test.cc
@@ -62,7 +62,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitInitializer_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
     WrapInFunction(Expr(f16((1 << 15) - 8)));
@@ -83,7 +83,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(Call<f16>(Expr(-1.2e-5_h)));
 
@@ -130,7 +130,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Vec_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
 
@@ -151,7 +151,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitInitializer_Type_Mat_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
 
diff --git a/src/tint/writer/wgsl/generator_impl_literal_test.cc b/src/tint/writer/wgsl/generator_impl_literal_test.cc
index f96b09e..c660198 100644
--- a/src/tint/writer/wgsl/generator_impl_literal_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_literal_test.cc
@@ -155,7 +155,7 @@
 using WgslGenerator_F16LiteralTest = TestParamHelper<F16Data>;
 
 TEST_P(WgslGenerator_F16LiteralTest, Emit) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* v = Expr(GetParam().value);
 
diff --git a/src/tint/writer/wgsl/generator_impl_type_test.cc b/src/tint/writer/wgsl/generator_impl_type_test.cc
index bad1440..4f8740c 100644
--- a/src/tint/writer/wgsl/generator_impl_type_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_type_test.cc
@@ -88,7 +88,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto type = Alias("make_type_reachable", ty.f16())->type;
 
@@ -120,7 +120,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Matrix_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto type = Alias("make_type_reachable", ty.mat2x3<f16>())->type;
 
@@ -268,7 +268,7 @@
 TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithEntryPointAttributes) {
     auto* s = Structure(
         "S", utils::Vector{
-                 Member("a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kVertexIndex)}),
+                 Member("a", ty.u32(), utils::Vector{Builtin(builtin::BuiltinValue::kVertexIndex)}),
                  Member("b", ty.f32(), utils::Vector{Location(2_a)}),
              });
 
@@ -305,7 +305,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Vector_F16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto type = Alias("make_type_reachable", ty.vec3<f16>())->type;
 
diff --git a/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
index bf68420..f31aa65 100644
--- a/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
@@ -146,7 +146,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", Expr(1_h));
     Func("f", utils::Empty, ty.void_(),
@@ -226,7 +226,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", vec3<f16>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(),
@@ -287,7 +287,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f16) {
-    Enable(ast::Extension::kF16);
+    Enable(builtin::Extension::kF16);
 
     auto* C = Const("C", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(),