Import Tint changes from Dawn

Changes:
  - 3b2ce130b6ea810e881bac3cc9c0ba24a6d03314 Stay within lex'd token bounds. by dan sinclair <dsinclair@chromium.org>
  - 08659d098db1c66730bfb3185155e5ebbdf266ac tint/ast: Generate ast::TexelFormat from intrinsics.def by Ben Clayton <bclayton@google.com>
  - fe8e6ee6827ca214ac789765afc1b939f0c2228a tint/ast: Generate ast::BuiltinValue from intrinsics.def by Ben Clayton <bclayton@google.com>
  - 9a6acc419eb550a46bf77c4174c521ddfc5ad98d tint: Add tint::OverrideId by Ben Clayton <bclayton@google.com>
  - b2306e27fcc99443e5e73e0109e8bc018c1aae8b Drop line and col in intrinsic file by dan sinclair <dsinclair@chromium.org>
  - 8dbd4d028073c22594f4457ebd6c806afd439d41 Add storage_class error reporting to generators and trans... by dan sinclair <dsinclair@chromium.org>
  - f330229de5a135f4430756dd3d244bd1bddae6a4 tint/ast: Rename Builtin to BuiltinValue by Ben Clayton <bclayton@google.com>
  - f50d56aa05a63b614c49adaab5f3ced3b100ceb1 tint/ast: Generate ast::Extension from intrinsics.def by Ben Clayton <bclayton@google.com>
  - a1571ac40308b2551eb51201f00819ca49f7120e tint/inspector: Use a std::optional for workgroup_size by Ben Clayton <bclayton@google.com>
  - a123b892a57598308577be70286abf74f9c17c64 tint/ast: Generate ast::StorageClass from intrinsics.def by Ben Clayton <bclayton@google.com>
  - bf8ee3549875457ee5019b83923bf0205763cfab const eval of clamp by Antonio Maiorano <amaiorano@google.com>
  - 4de90f0bb158271919658ec169bd9ba24ebb3d0c const eval of atan2 by Antonio Maiorano <amaiorano@google.com>
GitOrigin-RevId: 3b2ce130b6ea810e881bac3cc9c0ba24a6d03314
Change-Id: I2e50cb137494bd180c00ae9f491767eba5ed5c92
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/97383
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/include/tint/override_id.h b/include/tint/override_id.h
new file mode 100644
index 0000000..957673d
--- /dev/null
+++ b/include/tint/override_id.h
@@ -0,0 +1,60 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_OVERRIDE_ID_H_
+#define SRC_TINT_OVERRIDE_ID_H_
+
+#include <stdint.h>
+
+namespace tint {
+
+/// OverrideId is a numerical identifier for an override variable, unique per program.
+struct OverrideId {
+    uint16_t value = 0;
+};
+
+/// Equality operator for OverrideId
+/// @param lhs the OverrideId on the left of the '=' operator
+/// @param rhs the OverrideId on the right of the '=' operator
+/// @returns true if `lhs` is equal to `rhs`
+inline bool operator==(OverrideId lhs, OverrideId rhs) {
+    return lhs.value == rhs.value;
+}
+
+/// Less-than operator for OverrideId
+/// @param lhs the OverrideId on the left of the '<' operator
+/// @param rhs the OverrideId on the right of the '<' operator
+/// @returns true if `lhs` comes before `rhs`
+inline bool operator<(OverrideId lhs, OverrideId rhs) {
+    return lhs.value < rhs.value;
+}
+
+}  // namespace tint
+
+namespace std {
+
+/// Custom std::hash specialization for tint::OverrideId.
+template <>
+class hash<tint::OverrideId> {
+  public:
+    /// @param id the override identifier
+    /// @return the hash of the override identifier
+    inline std::size_t operator()(tint::OverrideId id) const {
+        return std::hash<decltype(tint::OverrideId::value)>()(id.value);
+    }
+};
+
+}  // namespace std
+
+#endif  // SRC_TINT_OVERRIDE_ID_H_
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 3290694..bb017a1 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -205,10 +205,10 @@
     "ast/bool_literal_expression.h",
     "ast/break_statement.cc",
     "ast/break_statement.h",
-    "ast/builtin.cc",
-    "ast/builtin.h",
     "ast/builtin_attribute.cc",
     "ast/builtin_attribute.h",
+    "ast/builtin_value.cc",
+    "ast/builtin_value.h",
     "ast/call_expression.cc",
     "ast/call_expression.h",
     "ast/call_statement.cc",
@@ -328,6 +328,8 @@
     "ast/struct_member_size_attribute.h",
     "ast/switch_statement.cc",
     "ast/switch_statement.h",
+    "ast/texel_format.cc",
+    "ast/texel_format.h",
     "ast/texture.cc",
     "ast/texture.h",
     "ast/traverse_expressions.h",
@@ -1002,6 +1004,7 @@
       "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_statement_test.cc",
@@ -1043,6 +1046,7 @@
       "ast/sampled_texture_test.cc",
       "ast/sampler_test.cc",
       "ast/stage_attribute_test.cc",
+      "ast/storage_class_test.cc",
       "ast/storage_texture_test.cc",
       "ast/stride_attribute_test.cc",
       "ast/struct_member_align_attribute_test.cc",
@@ -1052,6 +1056,7 @@
       "ast/struct_test.cc",
       "ast/switch_statement_test.cc",
       "ast/test_helper.h",
+      "ast/texel_format_test.cc",
       "ast/texture_test.cc",
       "ast/traverse_expressions_test.cc",
       "ast/u32_test.cc",
@@ -1109,7 +1114,7 @@
       "resolver/is_host_shareable_test.cc",
       "resolver/is_storeable_test.cc",
       "resolver/materialize_test.cc",
-      "resolver/pipeline_overridable_constant_test.cc",
+      "resolver/override_test.cc",
       "resolver/ptr_ref_test.cc",
       "resolver/ptr_ref_validation_test.cc",
       "resolver/resolver_behavior_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 8f8f19c..b5c32d7 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -77,8 +77,8 @@
   ast/break_statement.h
   ast/builtin_attribute.cc
   ast/builtin_attribute.h
-  ast/builtin.cc
-  ast/builtin.h
+  ast/builtin_value.cc
+  ast/builtin_value.h
   ast/call_expression.cc
   ast/call_expression.h
   ast/call_statement.cc
@@ -198,6 +198,8 @@
   ast/struct.h
   ast/switch_statement.cc
   ast/switch_statement.h
+  ast/texel_format.cc
+  ast/texel_format.h
   ast/texture.cc
   ast/texture.h
   ast/traverse_expressions.h
@@ -698,6 +700,7 @@
     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_statement_test.cc
@@ -739,6 +742,7 @@
     ast/sampled_texture_test.cc
     ast/sampler_test.cc
     ast/stage_attribute_test.cc
+    ast/storage_class_test.cc
     ast/storage_texture_test.cc
     ast/stride_attribute_test.cc
     ast/struct_member_align_attribute_test.cc
@@ -748,6 +752,7 @@
     ast/struct_test.cc
     ast/switch_statement_test.cc
     ast/test_helper.h
+    ast/texel_format_test.cc
     ast/texture_test.cc
     ast/traverse_expressions_test.cc
     ast/u32_test.cc
@@ -793,7 +798,7 @@
     resolver/is_host_shareable_test.cc
     resolver/is_storeable_test.cc
     resolver/materialize_test.cc
-    resolver/pipeline_overridable_constant_test.cc
+    resolver/override_test.cc
     resolver/ptr_ref_test.cc
     resolver/ptr_ref_validation_test.cc
     resolver/resolver_behavior_test.cc
@@ -1277,6 +1282,9 @@
 
   set(TINT_BENCHMARK_SRC
     "castable_bench.cc"
+    "ast/extension_bench.cc"
+    "ast/storage_class_bench.cc"
+    "ast/texel_format_bench.cc"
     "bench/benchmark.cc"
     "reader/wgsl/parser_bench.cc"
   )
diff --git a/src/tint/ast/builtin.cc b/src/tint/ast/builtin.cc
deleted file mode 100644
index d215a5c..0000000
--- a/src/tint/ast/builtin.cc
+++ /dev/null
@@ -1,80 +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/builtin.h"
-
-namespace tint::ast {
-
-std::ostream& operator<<(std::ostream& out, Builtin builtin) {
-    switch (builtin) {
-        case Builtin::kNone: {
-            out << "none";
-            break;
-        }
-        case Builtin::kPosition: {
-            out << "position";
-            break;
-        }
-        case Builtin::kVertexIndex: {
-            out << "vertex_index";
-            break;
-        }
-        case Builtin::kInstanceIndex: {
-            out << "instance_index";
-            break;
-        }
-        case Builtin::kFrontFacing: {
-            out << "front_facing";
-            break;
-        }
-        case Builtin::kFragDepth: {
-            out << "frag_depth";
-            break;
-        }
-        case Builtin::kLocalInvocationId: {
-            out << "local_invocation_id";
-            break;
-        }
-        case Builtin::kLocalInvocationIndex: {
-            out << "local_invocation_index";
-            break;
-        }
-        case Builtin::kGlobalInvocationId: {
-            out << "global_invocation_id";
-            break;
-        }
-        case Builtin::kWorkgroupId: {
-            out << "workgroup_id";
-            break;
-        }
-        case Builtin::kNumWorkgroups: {
-            out << "num_workgroups";
-            break;
-        }
-        case Builtin::kSampleIndex: {
-            out << "sample_index";
-            break;
-        }
-        case Builtin::kSampleMask: {
-            out << "sample_mask";
-            break;
-        }
-        case Builtin::kPointSize: {
-            out << "pointsize";
-        }
-    }
-    return out;
-}
-
-}  // namespace tint::ast
diff --git a/src/tint/ast/builtin.h b/src/tint/ast/builtin.h
deleted file mode 100644
index 699632a..0000000
--- a/src/tint/ast/builtin.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_TINT_AST_BUILTIN_H_
-#define SRC_TINT_AST_BUILTIN_H_
-
-#include <ostream>
-
-namespace tint::ast {
-
-/// The builtin identifiers
-enum class Builtin {
-    kNone = -1,
-    kPosition,
-    kVertexIndex,
-    kInstanceIndex,
-    kFrontFacing,
-    kFragDepth,
-    kLocalInvocationId,
-    kLocalInvocationIndex,
-    kGlobalInvocationId,
-    kWorkgroupId,
-    kNumWorkgroups,
-    kSampleIndex,
-    kSampleMask,
-
-    // Below are not currently WGSL builtins, but are included in this enum as
-    // they are used by certain backends.
-    kPointSize,
-};
-
-/// @param out the std::ostream to write to
-/// @param builtin the Builtin
-/// @return the std::ostream so calls can be chained
-std::ostream& operator<<(std::ostream& out, Builtin builtin);
-
-}  // namespace tint::ast
-
-#endif  // SRC_TINT_AST_BUILTIN_H_
diff --git a/src/tint/ast/builtin_attribute.cc b/src/tint/ast/builtin_attribute.cc
index 30e7cc6..d5aace0 100644
--- a/src/tint/ast/builtin_attribute.cc
+++ b/src/tint/ast/builtin_attribute.cc
@@ -22,7 +22,7 @@
 
 namespace tint::ast {
 
-BuiltinAttribute::BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, Builtin b)
+BuiltinAttribute::BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, 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 d0b3208..0aae24b 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.h"
+#include "src/tint/ast/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, Builtin builtin);
+    BuiltinAttribute(ProgramID pid, NodeID nid, const Source& src, 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 Builtin builtin;
+    const BuiltinValue builtin;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/builtin_attribute_test.cc b/src/tint/ast/builtin_attribute_test.cc
index a57f5b1..dba6997 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>(Builtin::kFragDepth);
-    EXPECT_EQ(Builtin::kFragDepth, d->builtin);
+    auto* d = create<BuiltinAttribute>(BuiltinValue::kFragDepth);
+    EXPECT_EQ(BuiltinValue::kFragDepth, d->builtin);
 }
 
 }  // namespace
diff --git a/src/tint/ast/builtin_texture_helper_test.h b/src/tint/ast/builtin_texture_helper_test.h
index d2737e1..1616a86 100644
--- a/src/tint/ast/builtin_texture_helper_test.h
+++ b/src/tint/ast/builtin_texture_helper_test.h
@@ -238,7 +238,7 @@
     Access const access = Access::kReadWrite;
     /// The image format for the storage texture
     /// Used only when texture_kind is kStorage
-    ast::TexelFormat const texel_format = ast::TexelFormat::kNone;
+    ast::TexelFormat const texel_format = ast::TexelFormat::kInvalid;
     /// The dimensions of the texture parameter
     ast::TextureDimension const texture_dimension;
     /// The data type of the texture parameter
diff --git a/src/tint/ast/builtin_value.cc b/src/tint/ast/builtin_value.cc
new file mode 100644
index 0000000..e8d6451
--- /dev/null
+++ b/src/tint/ast/builtin_value.cc
@@ -0,0 +1,104 @@
+// 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/builtin_value.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/builtin_value.h"
+
+namespace tint::ast {
+
+/// ParseBuiltinValue parses a BuiltinValue from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or BuiltinValue::kInvalid if the string could not be parsed.
+BuiltinValue ParseBuiltinValue(std::string_view str) {
+    if (str == "position") {
+        return BuiltinValue::kPosition;
+    }
+    if (str == "vertex_index") {
+        return BuiltinValue::kVertexIndex;
+    }
+    if (str == "instance_index") {
+        return BuiltinValue::kInstanceIndex;
+    }
+    if (str == "front_facing") {
+        return BuiltinValue::kFrontFacing;
+    }
+    if (str == "frag_depth") {
+        return BuiltinValue::kFragDepth;
+    }
+    if (str == "local_invocation_id") {
+        return BuiltinValue::kLocalInvocationId;
+    }
+    if (str == "local_invocation_index") {
+        return BuiltinValue::kLocalInvocationIndex;
+    }
+    if (str == "global_invocation_id") {
+        return BuiltinValue::kGlobalInvocationId;
+    }
+    if (str == "workgroup_id") {
+        return BuiltinValue::kWorkgroupId;
+    }
+    if (str == "num_workgroups") {
+        return BuiltinValue::kNumWorkgroups;
+    }
+    if (str == "sample_index") {
+        return BuiltinValue::kSampleIndex;
+    }
+    if (str == "sample_mask") {
+        return BuiltinValue::kSampleMask;
+    }
+    return BuiltinValue::kInvalid;
+}
+
+std::ostream& operator<<(std::ostream& out, BuiltinValue value) {
+    switch (value) {
+        case BuiltinValue::kInvalid:
+            return out << "invalid";
+        case BuiltinValue::kPosition:
+            return out << "position";
+        case BuiltinValue::kVertexIndex:
+            return out << "vertex_index";
+        case BuiltinValue::kInstanceIndex:
+            return out << "instance_index";
+        case BuiltinValue::kFrontFacing:
+            return out << "front_facing";
+        case BuiltinValue::kFragDepth:
+            return out << "frag_depth";
+        case BuiltinValue::kLocalInvocationId:
+            return out << "local_invocation_id";
+        case BuiltinValue::kLocalInvocationIndex:
+            return out << "local_invocation_index";
+        case BuiltinValue::kGlobalInvocationId:
+            return out << "global_invocation_id";
+        case BuiltinValue::kWorkgroupId:
+            return out << "workgroup_id";
+        case BuiltinValue::kNumWorkgroups:
+            return out << "num_workgroups";
+        case BuiltinValue::kSampleIndex:
+            return out << "sample_index";
+        case BuiltinValue::kSampleMask:
+            return out << "sample_mask";
+        case BuiltinValue::kPointSize:
+            return out << "point_size";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::ast
diff --git a/src/tint/ast/builtin_value.cc.tmpl b/src/tint/ast/builtin_value.cc.tmpl
new file mode 100644
index 0000000..7340c88
--- /dev/null
+++ b/src/tint/ast/builtin_value.cc.tmpl
@@ -0,0 +1,22 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "builtin_value") -}}
+
+#include "src/tint/ast/builtin_value.h"
+
+namespace tint::ast {
+
+{{ Eval "ParseEnum" $enum}}
+
+{{ Eval "EnumOStream" $enum}}
+
+}  // namespace tint::ast
diff --git a/src/tint/ast/builtin_value.h b/src/tint/ast/builtin_value.h
new file mode 100644
index 0000000..0a2c7f0
--- /dev/null
+++ b/src/tint/ast/builtin_value.h
@@ -0,0 +1,60 @@
+// 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.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/builtin_value.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_AST_BUILTIN_VALUE_H_
+#define SRC_TINT_AST_BUILTIN_VALUE_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Storage class of a given pointer.
+enum class BuiltinValue {
+    kInvalid,
+    kPosition,
+    kVertexIndex,
+    kInstanceIndex,
+    kFrontFacing,
+    kFragDepth,
+    kLocalInvocationId,
+    kLocalInvocationIndex,
+    kGlobalInvocationId,
+    kWorkgroupId,
+    kNumWorkgroups,
+    kSampleIndex,
+    kSampleMask,
+    kPointSize,  // Tint-internal enum entry - not parsed
+};
+
+/// @param out the std::ostream to write to
+/// @param value the BuiltinValue
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, BuiltinValue value);
+
+/// ParseBuiltinValue parses a BuiltinValue from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or BuiltinValue::kInvalid if the string could not be parsed.
+BuiltinValue ParseBuiltinValue(std::string_view str);
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_BUILTIN_VALUE_H_
diff --git a/src/tint/ast/builtin_value.h.tmpl b/src/tint/ast/builtin_value.h.tmpl
new file mode 100644
index 0000000..1985305
--- /dev/null
+++ b/src/tint/ast/builtin_value.h.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "builtin_value") -}}
+
+#ifndef SRC_TINT_AST_BUILTIN_VALUE_H_
+#define SRC_TINT_AST_BUILTIN_VALUE_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Storage class of a given pointer.
+{{ Eval "DeclareEnum" $enum}}
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_BUILTIN_VALUE_H_
diff --git a/src/tint/ast/builtin_value_bench.cc b/src/tint/ast/builtin_value_bench.cc
new file mode 100644
index 0000000..0a4048c
--- /dev/null
+++ b/src/tint/ast/builtin_value_bench.cc
@@ -0,0 +1,130 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/builtin_value_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/builtin_value.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+void BuiltinValueParser(::benchmark::State& state) {
+    std::array kStrings{
+        "pccsitin",
+        "oiti3",
+        "positVon",
+        "position",
+        "1osition",
+        "osJtqqon",
+        "llos77tion",
+        "vrtHHppx_index",
+        "vertx_icx",
+        "veGtex_bnde",
+        "vertex_index",
+        "vertex_inveii",
+        "veWWtex_ind8x",
+        "vxxrtMx_indx",
+        "isXance_indegg",
+        "insanc_iXVex",
+        "instance_in3ex",
+        "instance_index",
+        "instancE_index",
+        "nsTTance_PPndex",
+        "nstancxx_indddx",
+        "44ront_facing",
+        "fSSont_facinVV",
+        "fronR_Racing",
+        "front_facing",
+        "ron9_faciFg",
+        "front_facin",
+        "fVonRR_HaOing",
+        "fyag_epth",
+        "f77ag_nnellrrh",
+        "fra400depth",
+        "frag_depth",
+        "fa_epooh",
+        "frg_ezzth",
+        "f11a_eppiih",
+        "local_invXXcation_id",
+        "lIIcal_i5599ocation_inn",
+        "HHrrcal_inSSocation_Yaa",
+        "local_invocation_id",
+        "lokkal_invocatini",
+        "jocal_invocRRongid",
+        "local_inocatbon_i",
+        "local_injocation_index",
+        "local_invocatio_index",
+        "locl_invocqtion_ndex",
+        "local_invocation_index",
+        "localNNinvocaton_index",
+        "local_invocatin_ivvdx",
+        "locl_invocatioQQ_index",
+        "globalrnvocaton_iff",
+        "global_invocation_jd",
+        "NNlbal_wwnvocation82d",
+        "global_invocation_id",
+        "global_invocationid",
+        "globalrrinvocation_id",
+        "globaG_invocation_id",
+        "workgroupFFid",
+        "worgrupid",
+        "workgroup_rr",
+        "workgroup_id",
+        "workgrouid",
+        "DokgXoJJp_id",
+        "8orgrup_i",
+        "num_wkkr11up",
+        "numworkgroups",
+        "Ju_workgroups",
+        "num_workgroups",
+        "num_corkgroups",
+        "num_woOkgroups",
+        "num_workKK__vvttps",
+        "smple5inxxe8",
+        "s__mle_qFdex",
+        "saqqple_idex",
+        "sample_index",
+        "saOpe_33nde66",
+        "s6oople_indttQx",
+        "sam66le_inex",
+        "samxe66masOz",
+        "yyample_mask",
+        "amplZZHask",
+        "sample_mask",
+        "WWaple_maq4k",
+        "samplOO_ask",
+        "sYohpe_msk",
+    };
+    for (auto _ : state) {
+        for (auto& str : kStrings) {
+            auto result = ParseBuiltinValue(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK(BuiltinValueParser);
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/builtin_value_bench.cc.tmpl b/src/tint/ast/builtin_value_bench.cc.tmpl
new file mode 100644
index 0000000..f50bd20
--- /dev/null
+++ b/src/tint/ast/builtin_value_bench.cc.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value_bench.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "builtin_value") -}}
+
+#include "src/tint/ast/builtin_value.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "BenchmarkParseEnum" $enum }}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/builtin_value_test.cc b/src/tint/ast/builtin_value_test.cc
new file mode 100644
index 0000000..a29810a
--- /dev/null
+++ b/src/tint/ast/builtin_value_test.cc
@@ -0,0 +1,122 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/builtin_value_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/builtin_value.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    BuiltinValue value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"position", BuiltinValue::kPosition},
+    {"vertex_index", BuiltinValue::kVertexIndex},
+    {"instance_index", BuiltinValue::kInstanceIndex},
+    {"front_facing", BuiltinValue::kFrontFacing},
+    {"frag_depth", BuiltinValue::kFragDepth},
+    {"local_invocation_id", BuiltinValue::kLocalInvocationId},
+    {"local_invocation_index", BuiltinValue::kLocalInvocationIndex},
+    {"global_invocation_id", BuiltinValue::kGlobalInvocationId},
+    {"workgroup_id", BuiltinValue::kWorkgroupId},
+    {"num_workgroups", BuiltinValue::kNumWorkgroups},
+    {"sample_index", BuiltinValue::kSampleIndex},
+    {"sample_mask", BuiltinValue::kSampleMask},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"pccsitin", BuiltinValue::kInvalid},
+    {"oiti3", BuiltinValue::kInvalid},
+    {"positVon", BuiltinValue::kInvalid},
+    {"1ertex_index", BuiltinValue::kInvalid},
+    {"vertex_Jnqex", BuiltinValue::kInvalid},
+    {"velltex_inde77", BuiltinValue::kInvalid},
+    {"inpptanceqHHindx", BuiltinValue::kInvalid},
+    {"cnsanvendex", BuiltinValue::kInvalid},
+    {"istancG_index", BuiltinValue::kInvalid},
+    {"front_facvnii", BuiltinValue::kInvalid},
+    {"frWWnt_faci8g", BuiltinValue::kInvalid},
+    {"fxxonM_facig", BuiltinValue::kInvalid},
+    {"fXag_detgg", BuiltinValue::kInvalid},
+    {"fag_XuVh", BuiltinValue::kInvalid},
+    {"frag_dept3", BuiltinValue::kInvalid},
+    {"local_Envocation_id", BuiltinValue::kInvalid},
+    {"localiPPvocatioTT_id", BuiltinValue::kInvalid},
+    {"localxxnvocationddid", BuiltinValue::kInvalid},
+    {"loca44_invocation_index", BuiltinValue::kInvalid},
+    {"local_invocSStionVVindex", BuiltinValue::kInvalid},
+    {"locRR_invocat22n_index", BuiltinValue::kInvalid},
+    {"globalFinvoction_id", BuiltinValue::kInvalid},
+    {"gloal_invocation_id", BuiltinValue::kInvalid},
+    {"RRlHOOaV_invoction_id", BuiltinValue::kInvalid},
+    {"workgyoup_i", BuiltinValue::kInvalid},
+    {"wnrrrkg77loup_Gd", BuiltinValue::kInvalid},
+    {"00orkgr4up_id", BuiltinValue::kInvalid},
+    {"numwroogrops", BuiltinValue::kInvalid},
+    {"nzm_wokgroups", BuiltinValue::kInvalid},
+    {"uippworkgro11ps", BuiltinValue::kInvalid},
+    {"sample_iXXdex", BuiltinValue::kInvalid},
+    {"5nnample_99IIdex", BuiltinValue::kInvalid},
+    {"samYlaaHHrrndeSS", BuiltinValue::kInvalid},
+    {"aHkk_mask", BuiltinValue::kInvalid},
+    {"jRRmpl_gsk", BuiltinValue::kInvalid},
+    {"smple_mbk", BuiltinValue::kInvalid},
+};
+
+using BuiltinValueParseTest = testing::TestWithParam<Case>;
+
+TEST_P(BuiltinValueParseTest, Parse) {
+    const char* string = GetParam().string;
+    BuiltinValue expect = GetParam().value;
+    EXPECT_EQ(expect, ParseBuiltinValue(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, BuiltinValueParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, BuiltinValueParseTest, testing::ValuesIn(kInvalidCases));
+
+using BuiltinValuePrintTest = testing::TestWithParam<Case>;
+
+TEST_P(BuiltinValuePrintTest, Print) {
+    BuiltinValue value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, BuiltinValuePrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/builtin_value_test.cc.tmpl b/src/tint/ast/builtin_value_test.cc.tmpl
new file mode 100644
index 0000000..213a81b
--- /dev/null
+++ b/src/tint/ast/builtin_value_test.cc.tmpl
@@ -0,0 +1,27 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "builtin_value") -}}
+
+#include "src/tint/ast/builtin_value.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "TestParsePrintEnum" $enum}}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/extension.cc b/src/tint/ast/extension.cc
index f03e3a0..4283df1 100644
--- a/src/tint/ast/extension.cc
+++ b/src/tint/ast/extension.cc
@@ -12,40 +12,46 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/extension.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
 #include "src/tint/ast/extension.h"
 
 namespace tint::ast {
 
-Extension ParseExtension(const std::string& name) {
-    if (name == "chromium_experimental_dp4a") {
-        return Extension::kChromiumExperimentalDP4a;
-    }
-    if (name == "chromium_disable_uniformity_analysis") {
-        return Extension::kChromiumDisableUniformityAnalysis;
-    }
-    if (name == "f16") {
+/// ParseExtension parses a Extension from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or Extension::kInvalid if the string could not be parsed.
+Extension ParseExtension(std::string_view str) {
+    if (str == "f16") {
         return Extension::kF16;
     }
-    return Extension::kNone;
-}
-
-const char* str(Extension ext) {
-    switch (ext) {
-        case Extension::kChromiumExperimentalDP4a:
-            return "chromium_experimental_dp4a";
-        case Extension::kChromiumDisableUniformityAnalysis:
-            return "chromium_disable_uniformity_analysis";
-        case Extension::kF16:
-            return "f16";
-        case Extension::kNone:
-            return "<none>";
+    if (str == "chromium_experimental_dp4a") {
+        return Extension::kChromiumExperimentalDp4A;
     }
-    return "<unknown>";
+    if (str == "chromium_disable_uniformity_analysis") {
+        return Extension::kChromiumDisableUniformityAnalysis;
+    }
+    return Extension::kInvalid;
 }
 
-std::ostream& operator<<(std::ostream& out, Extension i) {
-    out << str(i);
-    return out;
+std::ostream& operator<<(std::ostream& out, Extension value) {
+    switch (value) {
+        case Extension::kInvalid:
+            return out << "invalid";
+        case Extension::kF16:
+            return out << "f16";
+        case Extension::kChromiumExperimentalDp4A:
+            return out << "chromium_experimental_dp4a";
+        case Extension::kChromiumDisableUniformityAnalysis:
+            return out << "chromium_disable_uniformity_analysis";
+    }
+    return out << "<unknown>";
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/extension.cc.tmpl b/src/tint/ast/extension.cc.tmpl
new file mode 100644
index 0000000..e0f319e
--- /dev/null
+++ b/src/tint/ast/extension.cc.tmpl
@@ -0,0 +1,22 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate extension.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "extension") -}}
+
+#include "src/tint/ast/extension.h"
+
+namespace tint::ast {
+
+{{ Eval "ParseEnum" $enum}}
+
+{{ Eval "EnumOStream" $enum}}
+
+}  // namespace tint::ast
diff --git a/src/tint/ast/extension.h b/src/tint/ast/extension.h
index 21e9ac1..32bf507 100644
--- a/src/tint/ast/extension.h
+++ b/src/tint/ast/extension.h
@@ -12,53 +12,41 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/extension.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
 #ifndef SRC_TINT_AST_EXTENSION_H_
 #define SRC_TINT_AST_EXTENSION_H_
 
-#include <sstream>
-#include <string>
+#include <ostream>
 
 #include "src/tint/utils/unique_vector.h"
 
 namespace tint::ast {
 
 /// An enumerator of WGSL extensions
+/// @see src/tint/intrinsics.def for extension descriptions
 enum class Extension {
-    /// WGSL Extension "f16"
+    kInvalid,
     kF16,
-
-    /// An extension for the experimental feature
-    /// "chromium_experimental_dp4a".
-    /// See crbug.com/tint/1497 for more details
-    kChromiumExperimentalDP4a,
-    /// A Chromium-specific extension for disabling uniformity analysis.
+    kChromiumExperimentalDp4A,
     kChromiumDisableUniformityAnalysis,
-
-    /// Reserved for representing "No extension required" or "Not a valid extension".
-    kNone,
 };
 
-/// Convert a string of extension name into one of Extension enum value, the result will be
-/// Extension::kNone if the name is not a known extension name. A extension node of kind
-/// kNone must not exist in the AST tree, and using a unknown extension name in WGSL code
-/// should result in a shader-creation error.
-/// @param name string of the extension name
-/// @return the Extension enum value for the extension of given name, or kNone if no known extension
-/// has the given name
-Extension ParseExtension(const std::string& name);
+/// @param out the std::ostream to write to
+/// @param value the Extension
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, Extension value);
 
-/// Convert the Extension enum value to corresponding extension name string.
-/// @param ext the Extension enum value
-/// @return string of the extension name corresponding to the given kind, or
-/// an empty string if the given enum value is kNone or don't have a
-/// known corresponding name
-const char* ExtensionName(Extension ext);
-
-/// @returns the name of the extension.
-const char* str(Extension i);
-
-/// Emits the name of the extension type.
-std::ostream& operator<<(std::ostream& out, Extension i);
+/// ParseExtension parses a Extension from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or Extension::kInvalid if the string could not be parsed.
+Extension ParseExtension(std::string_view str);
 
 // A unique vector of extensions
 using Extensions = utils::UniqueVector<Extension>;
diff --git a/src/tint/ast/extension.h.tmpl b/src/tint/ast/extension.h.tmpl
new file mode 100644
index 0000000..395aeec
--- /dev/null
+++ b/src/tint/ast/extension.h.tmpl
@@ -0,0 +1,32 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate extension.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "extension") -}}
+
+#ifndef SRC_TINT_AST_EXTENSION_H_
+#define SRC_TINT_AST_EXTENSION_H_
+
+#include <ostream>
+
+#include "src/tint/utils/unique_vector.h"
+
+namespace tint::ast {
+
+/// An enumerator of WGSL extensions
+/// @see src/tint/intrinsics.def for extension descriptions
+{{ Eval "DeclareEnum" $enum}}
+
+// A unique vector of extensions
+using Extensions = utils::UniqueVector<Extension>;
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_EXTENSION_H_
diff --git a/src/tint/ast/extension_bench.cc b/src/tint/ast/extension_bench.cc
new file mode 100644
index 0000000..47787e3
--- /dev/null
+++ b/src/tint/ast/extension_bench.cc
@@ -0,0 +1,67 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/extension_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/extension.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+void ExtensionParser(::benchmark::State& state) {
+    std::array kStrings{
+        "cc6",
+        "s",
+        "HH6",
+        "f16",
+        "116",
+        "qJ6",
+        "f17ll",
+        "chromippHm_experqqmetal_dp4a",
+        "chrmium_expecimntal_dp4",
+        "chrmiumGexpebimental_dp4a",
+        "chromium_experimental_dp4a",
+        "chromium_exverimentiil_dp4a",
+        "chro8ium_experimenWWal_dp4a",
+        "chromiMm_eperimxxntal_dp4a",
+        "chXggmium_disable_uniformity_aalysis",
+        "Xhomiuu_disale_uniformity_analysis",
+        "chromium_3isable_uniformity_analysis",
+        "chromium_disable_uniformity_analysis",
+        "chromiuE_disable_uniformity_analysis",
+        "chromium_disable_uniTTormity_aPPalsis",
+        "ddhromium_disabexxuniformity_analysis",
+    };
+    for (auto _ : state) {
+        for (auto& str : kStrings) {
+            auto result = ParseExtension(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK(ExtensionParser);
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/extension_bench.cc.tmpl b/src/tint/ast/extension_bench.cc.tmpl
new file mode 100644
index 0000000..af3dc95
--- /dev/null
+++ b/src/tint/ast/extension_bench.cc.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate extension_bench.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "extension") -}}
+
+#include "src/tint/ast/extension.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "BenchmarkParseEnum" $enum }}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/extension_test.cc b/src/tint/ast/extension_test.cc
index ed27674..8c75613 100644
--- a/src/tint/ast/extension_test.cc
+++ b/src/tint/ast/extension_test.cc
@@ -1,4 +1,3 @@
-
 // Copyright 2021 The Tint Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,24 +12,75 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/extension_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
 #include "src/tint/ast/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 {
 
-TEST(ExtensionTest, NameToKind_InvalidName) {
-    EXPECT_EQ(ParseExtension("f16"), Extension::kF16);
-    EXPECT_EQ(ParseExtension(""), Extension::kNone);
-    EXPECT_EQ(ParseExtension("__ImpossibleExtensionName"), Extension::kNone);
-    EXPECT_EQ(ParseExtension("123"), Extension::kNone);
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    Extension value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
 }
 
-TEST(ExtensionTest, KindToName) {
-    EXPECT_EQ(std::string(str(Extension::kF16)), "f16");
-    EXPECT_EQ(std::string(str(Extension::kNone)), "<none>");
+static constexpr Case kValidCases[] = {
+    {"f16", Extension::kF16},
+    {"chromium_experimental_dp4a", Extension::kChromiumExperimentalDp4A},
+    {"chromium_disable_uniformity_analysis", Extension::kChromiumDisableUniformityAnalysis},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"cc6", Extension::kInvalid},
+    {"s", Extension::kInvalid},
+    {"HH6", Extension::kInvalid},
+    {"chro1ium_experimental_dp4a", Extension::kInvalid},
+    {"chrJmium_experiqqetal_dp4a", Extension::kInvalid},
+    {"chromium_experimenll77l_dp4a", Extension::kInvalid},
+    {"chromiumppdisableqquniformity_aalysHHs", Extension::kInvalid},
+    {"chromiu_disable_unifovmitc_analyi", Extension::kInvalid},
+    {"chromium_diable_uGbformity_analysis", Extension::kInvalid},
+};
+
+using ExtensionParseTest = testing::TestWithParam<Case>;
+
+TEST_P(ExtensionParseTest, Parse) {
+    const char* string = GetParam().string;
+    Extension expect = GetParam().value;
+    EXPECT_EQ(expect, ParseExtension(string));
 }
 
+INSTANTIATE_TEST_SUITE_P(ValidCases, ExtensionParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, ExtensionParseTest, testing::ValuesIn(kInvalidCases));
+
+using ExtensionPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(ExtensionPrintTest, Print) {
+    Extension value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, ExtensionPrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
 }  // namespace
 }  // namespace tint::ast
diff --git a/src/tint/ast/extension_test.cc.tmpl b/src/tint/ast/extension_test.cc.tmpl
new file mode 100644
index 0000000..8c7a6af
--- /dev/null
+++ b/src/tint/ast/extension_test.cc.tmpl
@@ -0,0 +1,27 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate extension_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "extension") -}}
+
+#include "src/tint/ast/extension.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "TestParsePrintEnum" $enum}}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/storage_class.cc b/src/tint/ast/storage_class.cc
index 903d27a..303c04e 100644
--- a/src/tint/ast/storage_class.cc
+++ b/src/tint/ast/storage_class.cc
@@ -12,6 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/storage_class.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
 #include "src/tint/ast/storage_class.h"
 
 namespace tint::ast {
diff --git a/src/tint/ast/storage_class.cc.tmpl b/src/tint/ast/storage_class.cc.tmpl
new file mode 100644
index 0000000..e2903b7
--- /dev/null
+++ b/src/tint/ast/storage_class.cc.tmpl
@@ -0,0 +1,25 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate storage_class.cc
+
+To update the generated file, run:
+    ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "storage_class") -}}
+
+#include "src/tint/ast/storage_class.h"
+
+namespace tint::ast {
+
+{{ Eval "ParseEnum" $enum}}
+
+{{ Eval "EnumOStream" $enum}}
+
+}  // namespace tint::ast
diff --git a/src/tint/ast/storage_class.h b/src/tint/ast/storage_class.h
index 7451587..cb21115 100644
--- a/src/tint/ast/storage_class.h
+++ b/src/tint/ast/storage_class.h
@@ -12,6 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/storage_class.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
 #ifndef SRC_TINT_AST_STORAGE_CLASS_H_
 #define SRC_TINT_AST_STORAGE_CLASS_H_
 
@@ -22,21 +30,21 @@
 /// Storage class of a given pointer.
 enum class StorageClass {
     kInvalid,
-    kNone,
+    kNone,  // Tint-internal enum entry - not parsed
     kFunction,
     kPrivate,
     kWorkgroup,
     kUniform,
     kStorage,
-    kHandle,
-    kIn,
-    kOut,
+    kHandle,  // Tint-internal enum entry - not parsed
+    kIn,  // Tint-internal enum entry - not parsed
+    kOut,  // Tint-internal enum entry - not parsed
 };
 
 /// @param out the std::ostream to write to
-/// @param sc the StorageClass
-/// @return the std::ostream so calls can be chained
-std::ostream& operator<<(std::ostream& out, StorageClass sc);
+/// @param value the StorageClass
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, StorageClass value);
 
 /// ParseStorageClass parses a StorageClass from a string.
 /// @param str the string to parse
diff --git a/src/tint/ast/storage_class.h.tmpl b/src/tint/ast/storage_class.h.tmpl
new file mode 100644
index 0000000..d885c72
--- /dev/null
+++ b/src/tint/ast/storage_class.h.tmpl
@@ -0,0 +1,36 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate storage_class.h
+
+To update the generated file, run:
+    ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "storage_class") -}}
+
+#ifndef SRC_TINT_AST_STORAGE_CLASS_H_
+#define SRC_TINT_AST_STORAGE_CLASS_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Storage class of a given pointer.
+{{ Eval "DeclareEnum" $enum}}
+
+/// @returns true if the StorageClass is host-shareable
+/// @param sc the StorageClass
+/// @see https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable
+inline bool IsHostShareable(StorageClass sc) {
+    return sc == ast::StorageClass::kUniform || sc == ast::StorageClass::kStorage;
+}
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_STORAGE_CLASS_H_
diff --git a/src/tint/ast/storage_class_bench.cc b/src/tint/ast/storage_class_bench.cc
new file mode 100644
index 0000000..d1232df
--- /dev/null
+++ b/src/tint/ast/storage_class_bench.cc
@@ -0,0 +1,81 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/storage_class_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/storage_class.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+void StorageClassParser(::benchmark::State& state) {
+    std::array kStrings{
+        "fccnctin",
+        "ucti3",
+        "functVon",
+        "function",
+        "1unction",
+        "unJtqqon",
+        "llun77tion",
+        "ppqqivtHH",
+        "prcv",
+        "bivaGe",
+        "private",
+        "priviive",
+        "8WWivate",
+        "pxxvate",
+        "wXkgrggup",
+        "worXVup",
+        "3orkgroup",
+        "workgroup",
+        "workgroEp",
+        "woTTPkroup",
+        "ddorkroxxp",
+        "u44iform",
+        "unSSfoVVm",
+        "RniR22m",
+        "uniform",
+        "uFfo9m",
+        "uniorm",
+        "VOORRHrm",
+        "straye",
+        "llntrrr77ge",
+        "stor4g00",
+        "storage",
+        "trooe",
+        "zzrage",
+        "siioppa1",
+    };
+    for (auto _ : state) {
+        for (auto& str : kStrings) {
+            auto result = ParseStorageClass(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK(StorageClassParser);
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/storage_class_bench.cc.tmpl b/src/tint/ast/storage_class_bench.cc.tmpl
new file mode 100644
index 0000000..d9ea8cb
--- /dev/null
+++ b/src/tint/ast/storage_class_bench.cc.tmpl
@@ -0,0 +1,29 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate storage_class_bench.cc
+
+To update the generated file, run:
+    ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "storage_class") -}}
+
+#include "src/tint/ast/storage_class.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "BenchmarkParseEnum" $enum }}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/storage_class_test.cc b/src/tint/ast/storage_class_test.cc
new file mode 100644
index 0000000..2085168
--- /dev/null
+++ b/src/tint/ast/storage_class_test.cc
@@ -0,0 +1,94 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/storage_class_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/storage_class.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    StorageClass value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"function", StorageClass::kFunction},
+    {"private", StorageClass::kPrivate},
+    {"workgroup", StorageClass::kWorkgroup},
+    {"uniform", StorageClass::kUniform},
+    {"storage", StorageClass::kStorage},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"fccnctin", StorageClass::kInvalid},
+    {"ucti3", StorageClass::kInvalid},
+    {"functVon", StorageClass::kInvalid},
+    {"priv1te", StorageClass::kInvalid},
+    {"pqiJate", StorageClass::kInvalid},
+    {"privat7ll", StorageClass::kInvalid},
+    {"workroppqHH", StorageClass::kInvalid},
+    {"workru", StorageClass::kInvalid},
+    {"wbkgGoup", StorageClass::kInvalid},
+    {"unifiivm", StorageClass::kInvalid},
+    {"8WWiform", StorageClass::kInvalid},
+    {"uxxform", StorageClass::kInvalid},
+    {"sXraggg", StorageClass::kInvalid},
+    {"traXe", StorageClass::kInvalid},
+    {"stor3ge", StorageClass::kInvalid},
+};
+
+using StorageClassParseTest = testing::TestWithParam<Case>;
+
+TEST_P(StorageClassParseTest, Parse) {
+    const char* string = GetParam().string;
+    StorageClass expect = GetParam().value;
+    EXPECT_EQ(expect, ParseStorageClass(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, StorageClassParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, StorageClassParseTest, testing::ValuesIn(kInvalidCases));
+
+using StorageClassPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(StorageClassPrintTest, Print) {
+    StorageClass value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, StorageClassPrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/storage_class_test.cc.tmpl b/src/tint/ast/storage_class_test.cc.tmpl
new file mode 100644
index 0000000..3696aab
--- /dev/null
+++ b/src/tint/ast/storage_class_test.cc.tmpl
@@ -0,0 +1,30 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate storage_class_test.cc
+
+To update the generated file, run:
+    ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "storage_class") -}}
+
+#include "src/tint/ast/storage_class.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "TestParsePrintEnum" $enum}}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/storage_texture.cc b/src/tint/ast/storage_texture.cc
index d75bb0f..9c223c3 100644
--- a/src/tint/ast/storage_texture.cc
+++ b/src/tint/ast/storage_texture.cc
@@ -23,65 +23,6 @@
 
 namespace tint::ast {
 
-// Note, these names match the names in the WGSL spec. This behaviour is used
-// in the WGSL writer to emit the texture format names.
-std::ostream& operator<<(std::ostream& out, TexelFormat format) {
-    switch (format) {
-        case TexelFormat::kNone:
-            out << "none";
-            break;
-        case TexelFormat::kR32Uint:
-            out << "r32uint";
-            break;
-        case TexelFormat::kR32Sint:
-            out << "r32sint";
-            break;
-        case TexelFormat::kR32Float:
-            out << "r32float";
-            break;
-        case TexelFormat::kRgba8Unorm:
-            out << "rgba8unorm";
-            break;
-        case TexelFormat::kRgba8Snorm:
-            out << "rgba8snorm";
-            break;
-        case TexelFormat::kRgba8Uint:
-            out << "rgba8uint";
-            break;
-        case TexelFormat::kRgba8Sint:
-            out << "rgba8sint";
-            break;
-        case TexelFormat::kRg32Uint:
-            out << "rg32uint";
-            break;
-        case TexelFormat::kRg32Sint:
-            out << "rg32sint";
-            break;
-        case TexelFormat::kRg32Float:
-            out << "rg32float";
-            break;
-        case TexelFormat::kRgba16Uint:
-            out << "rgba16uint";
-            break;
-        case TexelFormat::kRgba16Sint:
-            out << "rgba16sint";
-            break;
-        case TexelFormat::kRgba16Float:
-            out << "rgba16float";
-            break;
-        case TexelFormat::kRgba32Uint:
-            out << "rgba32uint";
-            break;
-        case TexelFormat::kRgba32Sint:
-            out << "rgba32sint";
-            break;
-        case TexelFormat::kRgba32Float:
-            out << "rgba32float";
-            break;
-    }
-    return out;
-}
-
 StorageTexture::StorageTexture(ProgramID pid,
                                NodeID nid,
                                const Source& src,
@@ -135,7 +76,7 @@
             return builder.create<F32>();
         }
 
-        case TexelFormat::kNone:
+        case TexelFormat::kInvalid:
             break;
     }
 
diff --git a/src/tint/ast/storage_texture.h b/src/tint/ast/storage_texture.h
index ac7fee1..9ae7b95 100644
--- a/src/tint/ast/storage_texture.h
+++ b/src/tint/ast/storage_texture.h
@@ -18,36 +18,11 @@
 #include <string>
 
 #include "src/tint/ast/access.h"
+#include "src/tint/ast/texel_format.h"
 #include "src/tint/ast/texture.h"
 
 namespace tint::ast {
 
-/// The texel format in the storage texture
-enum class TexelFormat {
-    kNone = -1,
-    kRgba8Unorm,
-    kRgba8Snorm,
-    kRgba8Uint,
-    kRgba8Sint,
-    kRgba16Uint,
-    kRgba16Sint,
-    kRgba16Float,
-    kR32Uint,
-    kR32Sint,
-    kR32Float,
-    kRg32Uint,
-    kRg32Sint,
-    kRg32Float,
-    kRgba32Uint,
-    kRgba32Sint,
-    kRgba32Float,
-};
-
-/// @param out the std::ostream to write to
-/// @param format the TexelFormat
-/// @return the std::ostream so calls can be chained
-std::ostream& operator<<(std::ostream& out, TexelFormat format);
-
 /// A storage texture type.
 class StorageTexture final : public Castable<StorageTexture, Texture> {
   public:
diff --git a/src/tint/ast/texel_format.cc b/src/tint/ast/texel_format.cc
new file mode 100644
index 0000000..cfac9f1
--- /dev/null
+++ b/src/tint/ast/texel_format.cc
@@ -0,0 +1,122 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/texel_format.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/texel_format.h"
+
+namespace tint::ast {
+
+/// ParseTexelFormat parses a TexelFormat from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or TexelFormat::kInvalid if the string could not be parsed.
+TexelFormat ParseTexelFormat(std::string_view str) {
+    if (str == "rgba8unorm") {
+        return TexelFormat::kRgba8Unorm;
+    }
+    if (str == "rgba8snorm") {
+        return TexelFormat::kRgba8Snorm;
+    }
+    if (str == "rgba8uint") {
+        return TexelFormat::kRgba8Uint;
+    }
+    if (str == "rgba8sint") {
+        return TexelFormat::kRgba8Sint;
+    }
+    if (str == "rgba16uint") {
+        return TexelFormat::kRgba16Uint;
+    }
+    if (str == "rgba16sint") {
+        return TexelFormat::kRgba16Sint;
+    }
+    if (str == "rgba16float") {
+        return TexelFormat::kRgba16Float;
+    }
+    if (str == "r32uint") {
+        return TexelFormat::kR32Uint;
+    }
+    if (str == "r32sint") {
+        return TexelFormat::kR32Sint;
+    }
+    if (str == "r32float") {
+        return TexelFormat::kR32Float;
+    }
+    if (str == "rg32uint") {
+        return TexelFormat::kRg32Uint;
+    }
+    if (str == "rg32sint") {
+        return TexelFormat::kRg32Sint;
+    }
+    if (str == "rg32float") {
+        return TexelFormat::kRg32Float;
+    }
+    if (str == "rgba32uint") {
+        return TexelFormat::kRgba32Uint;
+    }
+    if (str == "rgba32sint") {
+        return TexelFormat::kRgba32Sint;
+    }
+    if (str == "rgba32float") {
+        return TexelFormat::kRgba32Float;
+    }
+    return TexelFormat::kInvalid;
+}
+
+std::ostream& operator<<(std::ostream& out, TexelFormat value) {
+    switch (value) {
+        case TexelFormat::kInvalid:
+            return out << "invalid";
+        case TexelFormat::kRgba8Unorm:
+            return out << "rgba8unorm";
+        case TexelFormat::kRgba8Snorm:
+            return out << "rgba8snorm";
+        case TexelFormat::kRgba8Uint:
+            return out << "rgba8uint";
+        case TexelFormat::kRgba8Sint:
+            return out << "rgba8sint";
+        case TexelFormat::kRgba16Uint:
+            return out << "rgba16uint";
+        case TexelFormat::kRgba16Sint:
+            return out << "rgba16sint";
+        case TexelFormat::kRgba16Float:
+            return out << "rgba16float";
+        case TexelFormat::kR32Uint:
+            return out << "r32uint";
+        case TexelFormat::kR32Sint:
+            return out << "r32sint";
+        case TexelFormat::kR32Float:
+            return out << "r32float";
+        case TexelFormat::kRg32Uint:
+            return out << "rg32uint";
+        case TexelFormat::kRg32Sint:
+            return out << "rg32sint";
+        case TexelFormat::kRg32Float:
+            return out << "rg32float";
+        case TexelFormat::kRgba32Uint:
+            return out << "rgba32uint";
+        case TexelFormat::kRgba32Sint:
+            return out << "rgba32sint";
+        case TexelFormat::kRgba32Float:
+            return out << "rgba32float";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::ast
diff --git a/src/tint/ast/texel_format.cc.tmpl b/src/tint/ast/texel_format.cc.tmpl
new file mode 100644
index 0000000..cc9f769
--- /dev/null
+++ b/src/tint/ast/texel_format.cc.tmpl
@@ -0,0 +1,22 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate texel_format.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "texel_format") -}}
+
+#include "src/tint/ast/texel_format.h"
+
+namespace tint::ast {
+
+{{ Eval "ParseEnum" $enum}}
+
+{{ Eval "EnumOStream" $enum}}
+
+}  // namespace tint::ast
diff --git a/src/tint/ast/texel_format.h b/src/tint/ast/texel_format.h
new file mode 100644
index 0000000..28119b3
--- /dev/null
+++ b/src/tint/ast/texel_format.h
@@ -0,0 +1,63 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/texel_format.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_AST_TEXEL_FORMAT_H_
+#define SRC_TINT_AST_TEXEL_FORMAT_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Enumerator of texel formats
+enum class TexelFormat {
+    kInvalid,
+    kRgba8Unorm,
+    kRgba8Snorm,
+    kRgba8Uint,
+    kRgba8Sint,
+    kRgba16Uint,
+    kRgba16Sint,
+    kRgba16Float,
+    kR32Uint,
+    kR32Sint,
+    kR32Float,
+    kRg32Uint,
+    kRg32Sint,
+    kRg32Float,
+    kRgba32Uint,
+    kRgba32Sint,
+    kRgba32Float,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the TexelFormat
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, TexelFormat value);
+
+/// ParseTexelFormat parses a TexelFormat from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or TexelFormat::kInvalid if the string could not be parsed.
+TexelFormat ParseTexelFormat(std::string_view str);
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_TEXEL_FORMAT_H_
diff --git a/src/tint/ast/texel_format.h.tmpl b/src/tint/ast/texel_format.h.tmpl
new file mode 100644
index 0000000..e7454a0
--- /dev/null
+++ b/src/tint/ast/texel_format.h.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate texel_format.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "texel_format") -}}
+
+#ifndef SRC_TINT_AST_TEXEL_FORMAT_H_
+#define SRC_TINT_AST_TEXEL_FORMAT_H_
+
+#include <ostream>
+
+namespace tint::ast {
+
+/// Enumerator of texel formats
+{{ Eval "DeclareEnum" $enum}}
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_TEXEL_FORMAT_H_
diff --git a/src/tint/ast/texel_format_bench.cc b/src/tint/ast/texel_format_bench.cc
new file mode 100644
index 0000000..8dde6b2
--- /dev/null
+++ b/src/tint/ast/texel_format_bench.cc
@@ -0,0 +1,158 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/texel_format_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/texel_format.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+void TexelFormatParser(::benchmark::State& state) {
+    std::array kStrings{
+        "rgbaunccrm",
+        "rlbanr3",
+        "rVba8unorm",
+        "rgba8unorm",
+        "rgba1unorm",
+        "rgbJqqnorm",
+        "rgb7ll8unorm",
+        "rgqqappnoHHm",
+        "rv8scor",
+        "rgbbGsnrm",
+        "rgba8snorm",
+        "rgba8vniirm",
+        "rg8a8snoWWm",
+        "Mgbaxxnorm",
+        "rXa8uggnt",
+        "rgbXVut",
+        "3gba8uint",
+        "rgba8uint",
+        "rgba8uiEt",
+        "rgTTPauint",
+        "ddgbauixxt",
+        "44gba8sint",
+        "VVgbaSSsint",
+        "rba8si2Rt",
+        "rgba8sint",
+        "r9bFsint",
+        "rgba8int",
+        "rgVROOsHnt",
+        "ryba1uint",
+        "r77ba1nnullrrt",
+        "rgb4006uint",
+        "rgba16uint",
+        "rb1uioot",
+        "rga1uzznt",
+        "r11b1uppiit",
+        "XXgba16sint",
+        "IIgb9916nni55t",
+        "rYbaSSrrsiHHat",
+        "rgba16sint",
+        "rbkk6Hit",
+        "jgba1sgRR",
+        "rgbab6si",
+        "rgba16fljat",
+        "rgba6float",
+        "rbq6float",
+        "rgba16float",
+        "rgba1NNloat",
+        "rgbvv6flot",
+        "rgbaQQ6foat",
+        "r3ffir",
+        "r32uijt",
+        "rNNwuin8",
+        "r32uint",
+        "r32int",
+        "rrr2uint",
+        "G32uint",
+        "r32sinFF",
+        "32st",
+        "r3rrint",
+        "r32sint",
+        "2sint",
+        "D3siJJt",
+        "r38n",
+        "r211lk",
+        "r32floa",
+        "r3flJat",
+        "r32float",
+        "r32fcoat",
+        "r32floOt",
+        "r32floKK_vtt",
+        "rxx32ui8",
+        "Fg3qq__n",
+        "rg32iqqt",
+        "rg32uint",
+        "rg333uin6",
+        "rtto62u9QQt",
+        "rg366uin",
+        "rOx2si6zz",
+        "rg3yysint",
+        "rHHsint",
+        "rg32sint",
+        "qWW432snt",
+        "rg3OOsnt",
+        "g32siYt",
+        "g32flo",
+        "rg32foaF",
+        "rg32fwat",
+        "rg32float",
+        "G3fKoaff",
+        "KKgq2float",
+        "rg32mmlo3t",
+        "rgba32uit",
+        "rqba3uint",
+        "rgbabb2uin",
+        "rgba32uint",
+        "rba32iint",
+        "qgba32uiOt",
+        "rgba32uiTTvv",
+        "rgFFa32sint",
+        "rg00Q2sPnt",
+        "rgbaP2sint",
+        "rgba32sint",
+        "rgb77s2sint",
+        "rgba32sbbRRC",
+        "rgbXX32sint",
+        "rOOOba3CCqoat",
+        "rgbu32fsLt",
+        "rgba3Xfloat",
+        "rgba32float",
+        "rba32float",
+        "qqb3float",
+        "rgba32fl22at",
+    };
+    for (auto _ : state) {
+        for (auto& str : kStrings) {
+            auto result = ParseTexelFormat(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK(TexelFormatParser);
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/texel_format_bench.cc.tmpl b/src/tint/ast/texel_format_bench.cc.tmpl
new file mode 100644
index 0000000..4df62b4
--- /dev/null
+++ b/src/tint/ast/texel_format_bench.cc.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate texel_format_bench.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "texel_format") -}}
+
+#include "src/tint/ast/texel_format.h"
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "BenchmarkParseEnum" $enum }}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/texel_format_test.cc b/src/tint/ast/texel_format_test.cc
new file mode 100644
index 0000000..9603961
--- /dev/null
+++ b/src/tint/ast/texel_format_test.cc
@@ -0,0 +1,138 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/ast/texel_format_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/ast/texel_format.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    TexelFormat value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"rgba8unorm", TexelFormat::kRgba8Unorm},
+    {"rgba8snorm", TexelFormat::kRgba8Snorm},
+    {"rgba8uint", TexelFormat::kRgba8Uint},
+    {"rgba8sint", TexelFormat::kRgba8Sint},
+    {"rgba16uint", TexelFormat::kRgba16Uint},
+    {"rgba16sint", TexelFormat::kRgba16Sint},
+    {"rgba16float", TexelFormat::kRgba16Float},
+    {"r32uint", TexelFormat::kR32Uint},
+    {"r32sint", TexelFormat::kR32Sint},
+    {"r32float", TexelFormat::kR32Float},
+    {"rg32uint", TexelFormat::kRg32Uint},
+    {"rg32sint", TexelFormat::kRg32Sint},
+    {"rg32float", TexelFormat::kRg32Float},
+    {"rgba32uint", TexelFormat::kRgba32Uint},
+    {"rgba32sint", TexelFormat::kRgba32Sint},
+    {"rgba32float", TexelFormat::kRgba32Float},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"rgbaunccrm", TexelFormat::kInvalid},
+    {"rlbanr3", TexelFormat::kInvalid},
+    {"rVba8unorm", TexelFormat::kInvalid},
+    {"rgba1snorm", TexelFormat::kInvalid},
+    {"rgbJqqnorm", TexelFormat::kInvalid},
+    {"rgb7ll8snorm", TexelFormat::kInvalid},
+    {"rgbauippqHH", TexelFormat::kInvalid},
+    {"rgbaun", TexelFormat::kInvalid},
+    {"rba8Gint", TexelFormat::kInvalid},
+    {"rgvia8sint", TexelFormat::kInvalid},
+    {"rgba8WWint", TexelFormat::kInvalid},
+    {"rgbasxxMt", TexelFormat::kInvalid},
+    {"rXba16ungg", TexelFormat::kInvalid},
+    {"rba1XuVt", TexelFormat::kInvalid},
+    {"rgba16uin3", TexelFormat::kInvalid},
+    {"rgba16sinE", TexelFormat::kInvalid},
+    {"TTgba16sPPn", TexelFormat::kInvalid},
+    {"rgbad6xxint", TexelFormat::kInvalid},
+    {"rgba446float", TexelFormat::kInvalid},
+    {"SSVVba16float", TexelFormat::kInvalid},
+    {"rgbRR6float", TexelFormat::kInvalid},
+    {"rFui9t", TexelFormat::kInvalid},
+    {"r32int", TexelFormat::kInvalid},
+    {"VOORRHnt", TexelFormat::kInvalid},
+    {"r3siyt", TexelFormat::kInvalid},
+    {"lln3rrs77nt", TexelFormat::kInvalid},
+    {"r32s4n00", TexelFormat::kInvalid},
+    {"32ooat", TexelFormat::kInvalid},
+    {"r32fzzt", TexelFormat::kInvalid},
+    {"r3iippl1a", TexelFormat::kInvalid},
+    {"XXg32uint", TexelFormat::kInvalid},
+    {"rII39955nnnt", TexelFormat::kInvalid},
+    {"aagHH2uinYSS", TexelFormat::kInvalid},
+    {"rkk3it", TexelFormat::kInvalid},
+    {"gj3sRRn", TexelFormat::kInvalid},
+    {"r3bsnt", TexelFormat::kInvalid},
+    {"rg32flojt", TexelFormat::kInvalid},
+    {"r32floa", TexelFormat::kInvalid},
+    {"rg32lot", TexelFormat::kInvalid},
+    {"rgb3uit", TexelFormat::kInvalid},
+    {"rgjj3uint", TexelFormat::kInvalid},
+    {"rgb2urnff", TexelFormat::kInvalid},
+    {"rgba32sijt", TexelFormat::kInvalid},
+    {"NNgba32ww2t", TexelFormat::kInvalid},
+    {"rgba32snt", TexelFormat::kInvalid},
+    {"rgba32rrloat", TexelFormat::kInvalid},
+    {"rgGa32float", TexelFormat::kInvalid},
+    {"FFgba32float", TexelFormat::kInvalid},
+};
+
+using TexelFormatParseTest = testing::TestWithParam<Case>;
+
+TEST_P(TexelFormatParseTest, Parse) {
+    const char* string = GetParam().string;
+    TexelFormat expect = GetParam().value;
+    EXPECT_EQ(expect, ParseTexelFormat(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, TexelFormatParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, TexelFormatParseTest, testing::ValuesIn(kInvalidCases));
+
+using TexelFormatPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(TexelFormatPrintTest, Print) {
+    TexelFormat value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, TexelFormatPrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/texel_format_test.cc.tmpl b/src/tint/ast/texel_format_test.cc.tmpl
new file mode 100644
index 0000000..304cfeb
--- /dev/null
+++ b/src/tint/ast/texel_format_test.cc.tmpl
@@ -0,0 +1,27 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate texel_format_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+{{- $enum := (Sem.Enum "texel_format") -}}
+
+#include "src/tint/ast/texel_format.h"
+
+#include <string>
+
+#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string.h"
+
+namespace tint::ast {
+namespace {
+
+{{ Eval "TestParsePrintEnum" $enum}}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/variable_test.cc b/src/tint/ast/variable_test.cc
index 025fa6b..a54e869 100644
--- a/src/tint/ast/variable_test.cc
+++ b/src/tint/ast/variable_test.cc
@@ -95,7 +95,7 @@
     auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
                     AttributeList{
                         create<LocationAttribute>(1u),
-                        create<BuiltinAttribute>(Builtin::kPosition),
+                        create<BuiltinAttribute>(BuiltinValue::kPosition),
                         create<IdAttribute>(1200u),
                     });
 
diff --git a/src/tint/castable_bench.cc b/src/tint/castable_bench.cc
index 7c7e0ef..c9d0c43 100644
--- a/src/tint/castable_bench.cc
+++ b/src/tint/castable_bench.cc
@@ -12,7 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "bench/benchmark.h"
+#include <memory>
+
+#include "benchmark/benchmark.h"
+
+#include "src/tint/castable.h"
 
 namespace tint {
 namespace {
diff --git a/src/tint/fuzzers/tint_common_fuzzer.cc b/src/tint/fuzzers/tint_common_fuzzer.cc
index bbea6fc..f547d55 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.cc
+++ b/src/tint/fuzzers/tint_common_fuzzer.cc
@@ -219,12 +219,7 @@
     switch (output_) {
         case OutputFormat::kWGSL: {
 #if TINT_BUILD_WGSL_WRITER
-            auto result = writer::wgsl::Generate(&program, options_wgsl_);
-            generated_wgsl_ = std::move(result.wgsl);
-            if (!result.success) {
-                VALIDITY_ERROR(program.Diagnostics(),
-                               "WGSL writer errored on validated input:\n" + result.error);
-            }
+            writer::wgsl::Generate(&program, options_wgsl_);
 #endif  // TINT_BUILD_WGSL_WRITER
             break;
         }
@@ -232,10 +227,6 @@
 #if TINT_BUILD_SPV_WRITER
             auto result = writer::spirv::Generate(&program, options_spirv_);
             generated_spirv_ = std::move(result.spirv);
-            if (!result.success) {
-                VALIDITY_ERROR(program.Diagnostics(),
-                               "SPIR-V writer errored on validated input:\n" + result.error);
-            }
 
             if (!SPIRVToolsValidationCheck(program, generated_spirv_)) {
                 VALIDITY_ERROR(program.Diagnostics(),
@@ -247,12 +238,7 @@
         }
         case OutputFormat::kHLSL: {
 #if TINT_BUILD_HLSL_WRITER
-            auto result = writer::hlsl::Generate(&program, options_hlsl_);
-            generated_hlsl_ = std::move(result.hlsl);
-            if (!result.success) {
-                VALIDITY_ERROR(program.Diagnostics(),
-                               "HLSL writer errored on validated input:\n" + result.error);
-            }
+            writer::hlsl::Generate(&program, options_hlsl_);
 #endif  // TINT_BUILD_HLSL_WRITER
             break;
         }
@@ -266,12 +252,7 @@
                 input_program = &*flattened;
             }
 
-            auto result = writer::msl::Generate(input_program, options_msl_);
-            generated_msl_ = std::move(result.msl);
-            if (!result.success) {
-                VALIDITY_ERROR(input_program->Diagnostics(),
-                               "MSL writer errored on validated input:\n" + result.error);
-            }
+            writer::msl::Generate(input_program, options_msl_);
 #endif  // TINT_BUILD_MSL_WRITER
             break;
         }
@@ -287,10 +268,10 @@
     auto entry_points = inspector.GetEntryPoints();
     CHECK_INSPECTOR(program, inspector);
 
-    auto constant_ids = inspector.GetConstantIDs();
+    auto override_ids = inspector.GetOverrideDefaultValues();
     CHECK_INSPECTOR(program, inspector);
 
-    auto constant_name_to_id = inspector.GetConstantNameToIdMap();
+    auto override_name_to_id = inspector.GetNamedOverrideIds();
     CHECK_INSPECTOR(program, inspector);
 
     for (auto& ep : entry_points) {
diff --git a/src/tint/inspector/entry_point.h b/src/tint/inspector/entry_point.h
index 493a93f..5d119d4 100644
--- a/src/tint/inspector/entry_point.h
+++ b/src/tint/inspector/entry_point.h
@@ -15,10 +15,13 @@
 #ifndef SRC_TINT_INSPECTOR_ENTRY_POINT_H_
 #define SRC_TINT_INSPECTOR_ENTRY_POINT_H_
 
+#include <optional>
 #include <string>
 #include <tuple>
 #include <vector>
 
+#include "tint/override_id.h"
+
 #include "src/tint/ast/interpolate_attribute.h"
 #include "src/tint/ast/pipeline_stage.h"
 
@@ -92,14 +95,13 @@
 /// @returns the publicly visible equivalent
 InterpolationSampling ASTToInspectorInterpolationSampling(ast::InterpolationSampling sampling);
 
-/// Reflection data about a pipeline overridable constant referenced by an entry
-/// point
-struct OverridableConstant {
-    /// Name of the constant
+/// Reflection data about an override variable referenced by an entry point
+struct Override {
+    /// Name of the override
     std::string name;
 
-    /// ID of the constant
-    uint16_t numeric_id;
+    /// ID of the override
+    OverrideId id;
 
     /// Type of the scalar
     enum class Type {
@@ -112,17 +114,26 @@
     /// Type of the scalar
     Type type;
 
-    /// Does this pipeline overridable constant have an initializer?
+    /// Does this override have an initializer?
     bool is_initialized = false;
 
-    /// Does this pipeline overridable constant have a numeric ID specified
-    /// explicitly?
-    bool is_numeric_id_specified = false;
+    /// Does this override have a numeric ID specified explicitly?
+    bool is_id_specified = false;
 };
 
 /// The pipeline stage
 enum class PipelineStage { kVertex, kFragment, kCompute };
 
+/// WorkgroupSize describes the dimensions of the workgroup grid for a compute shader.
+struct WorkgroupSize {
+    /// The 'x' dimension of the workgroup grid
+    uint32_t x = 1;
+    /// The 'y' dimension of the workgroup grid
+    uint32_t y = 1;
+    /// The 'z' dimension of the workgroup grid
+    uint32_t z = 1;
+};
+
 /// Reflection data for an entry point in the shader.
 struct EntryPoint {
     /// Constructors
@@ -139,18 +150,16 @@
     std::string remapped_name;
     /// The entry point stage
     PipelineStage stage;
-    /// The workgroup x size
-    uint32_t workgroup_size_x = 0;
-    /// The workgroup y size
-    uint32_t workgroup_size_y = 0;
-    /// The workgroup z size
-    uint32_t workgroup_size_z = 0;
+    /// The workgroup size. If PipelineStage is kCompute and this holds no value, then the workgroup
+    /// size is derived from an override-expression. In this situation you first need to run the
+    /// tint::transform::SubstituteOverride transform before using the inspector.
+    std::optional<WorkgroupSize> workgroup_size;
     /// List of the input variable accessed via this entry point.
     std::vector<StageVariable> input_variables;
     /// List of the output variable accessed via this entry point.
     std::vector<StageVariable> output_variables;
     /// List of the pipeline overridable constants accessed via this entry point.
-    std::vector<OverridableConstant> overridable_constants;
+    std::vector<Override> overrides;
     /// Does the entry point use the sample_mask builtin as an input builtin
     /// variable.
     bool input_sample_mask_used = false;
@@ -166,12 +175,6 @@
     bool sample_index_used = false;
     /// Does the entry point use the num_workgroups builtin
     bool num_workgroups_used = false;
-
-    /// @returns the size of the workgroup in {x,y,z} format
-    std::tuple<uint32_t, uint32_t, uint32_t> workgroup_size() {
-        return std::tuple<uint32_t, uint32_t, uint32_t>(workgroup_size_x, workgroup_size_y,
-                                                        workgroup_size_z);
-    }
 };
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/inspector.cc b/src/tint/inspector/inspector.cc
index e92c087..ae56de5 100644
--- a/src/tint/inspector/inspector.cc
+++ b/src/tint/inspector/inspector.cc
@@ -148,29 +148,30 @@
         entry_point.remapped_name = program_->Symbols().NameFor(func->symbol);
 
         switch (func->PipelineStage()) {
-            case ast::PipelineStage::kCompute:
+            case ast::PipelineStage::kCompute: {
                 entry_point.stage = PipelineStage::kCompute;
+
+                auto wgsize = sem->WorkgroupSize();
+                if (!wgsize[0].overridable_const && !wgsize[1].overridable_const &&
+                    !wgsize[2].overridable_const) {
+                    entry_point.workgroup_size = {wgsize[0].value, wgsize[1].value,
+                                                  wgsize[2].value};
+                }
                 break;
-            case ast::PipelineStage::kFragment:
+            }
+            case ast::PipelineStage::kFragment: {
                 entry_point.stage = PipelineStage::kFragment;
                 break;
-            case ast::PipelineStage::kVertex:
+            }
+            case ast::PipelineStage::kVertex: {
                 entry_point.stage = PipelineStage::kVertex;
                 break;
-            default:
+            }
+            default: {
                 TINT_UNREACHABLE(Inspector, diagnostics_)
                     << "invalid pipeline stage for entry point '" << entry_point.name << "'";
                 break;
-        }
-
-        auto wgsize = sem->WorkgroupSize();
-        entry_point.workgroup_size_x = wgsize[0].value;
-        entry_point.workgroup_size_y = wgsize[1].value;
-        entry_point.workgroup_size_z = wgsize[2].value;
-        if (wgsize[0].overridable_const || wgsize[1].overridable_const ||
-            wgsize[2].overridable_const) {
-            // TODO(crbug.com/tint/713): Handle overridable constants.
-            TINT_ASSERT(Inspector, false);
+            }
         }
 
         for (auto* param : sem->Parameters()) {
@@ -179,15 +180,15 @@
                                         entry_point.input_variables);
 
             entry_point.input_position_used |= ContainsBuiltin(
-                ast::Builtin::kPosition, param->Type(), param->Declaration()->attributes);
+                ast::BuiltinValue::kPosition, param->Type(), param->Declaration()->attributes);
             entry_point.front_facing_used |= ContainsBuiltin(
-                ast::Builtin::kFrontFacing, param->Type(), param->Declaration()->attributes);
+                ast::BuiltinValue::kFrontFacing, param->Type(), param->Declaration()->attributes);
             entry_point.sample_index_used |= ContainsBuiltin(
-                ast::Builtin::kSampleIndex, param->Type(), param->Declaration()->attributes);
+                ast::BuiltinValue::kSampleIndex, param->Type(), param->Declaration()->attributes);
             entry_point.input_sample_mask_used |= ContainsBuiltin(
-                ast::Builtin::kSampleMask, param->Type(), param->Declaration()->attributes);
+                ast::BuiltinValue::kSampleMask, param->Type(), param->Declaration()->attributes);
             entry_point.num_workgroups_used |= ContainsBuiltin(
-                ast::Builtin::kNumWorkgroups, param->Type(), param->Declaration()->attributes);
+                ast::BuiltinValue::kNumWorkgroups, param->Type(), param->Declaration()->attributes);
         }
 
         if (!sem->ReturnType()->Is<sem::Void>()) {
@@ -195,7 +196,7 @@
                                         entry_point.output_variables);
 
             entry_point.output_sample_mask_used = ContainsBuiltin(
-                ast::Builtin::kSampleMask, sem->ReturnType(), func->return_type_attributes);
+                ast::BuiltinValue::kSampleMask, sem->ReturnType(), func->return_type_attributes);
         }
 
         for (auto* var : sem->TransitivelyReferencedGlobals()) {
@@ -205,28 +206,28 @@
 
             auto* global = var->As<sem::GlobalVariable>();
             if (global && global->Declaration()->Is<ast::Override>()) {
-                OverridableConstant overridable_constant;
-                overridable_constant.name = name;
-                overridable_constant.numeric_id = global->ConstantId();
+                Override override;
+                override.name = name;
+                override.id = global->OverrideId();
                 auto* type = var->Type();
                 TINT_ASSERT(Inspector, type->is_scalar());
                 if (type->is_bool_scalar_or_vector()) {
-                    overridable_constant.type = OverridableConstant::Type::kBool;
+                    override.type = Override::Type::kBool;
                 } else if (type->is_float_scalar()) {
-                    overridable_constant.type = OverridableConstant::Type::kFloat32;
+                    override.type = Override::Type::kFloat32;
                 } else if (type->is_signed_integer_scalar()) {
-                    overridable_constant.type = OverridableConstant::Type::kInt32;
+                    override.type = Override::Type::kInt32;
                 } else if (type->is_unsigned_integer_scalar()) {
-                    overridable_constant.type = OverridableConstant::Type::kUint32;
+                    override.type = Override::Type::kUint32;
                 } else {
                     TINT_UNREACHABLE(Inspector, diagnostics_);
                 }
 
-                overridable_constant.is_initialized = global->Declaration()->constructor;
-                overridable_constant.is_numeric_id_specified =
+                override.is_initialized = global->Declaration()->constructor;
+                override.is_id_specified =
                     ast::HasAttribute<ast::IdAttribute>(global->Declaration()->attributes);
 
-                entry_point.overridable_constants.push_back(overridable_constant);
+                entry_point.overrides.push_back(override);
             }
         }
 
@@ -236,37 +237,37 @@
     return result;
 }
 
-std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
-    std::map<uint32_t, Scalar> result;
+std::map<OverrideId, Scalar> Inspector::GetOverrideDefaultValues() {
+    std::map<OverrideId, Scalar> result;
     for (auto* var : program_->AST().GlobalVariables()) {
         auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
         if (!global || !global->Declaration()->Is<ast::Override>()) {
             continue;
         }
 
-        // If there are conflicting defintions for a constant id, that is invalid
+        // If there are conflicting defintions for an override id, that is invalid
         // WGSL, so the resolver should catch it. Thus here the inspector just
-        // assumes all definitions of the constant id are the same, so only needs
-        // to find the first reference to constant id.
-        uint32_t constant_id = global->ConstantId();
-        if (result.find(constant_id) != result.end()) {
+        // assumes all definitions of the override id are the same, so only needs
+        // to find the first reference to override id.
+        OverrideId override_id = global->OverrideId();
+        if (result.find(override_id) != result.end()) {
             continue;
         }
 
         if (!var->constructor) {
-            result[constant_id] = Scalar();
+            result[override_id] = Scalar();
             continue;
         }
 
         auto* literal = var->constructor->As<ast::LiteralExpression>();
         if (!literal) {
             // This is invalid WGSL, but handling gracefully.
-            result[constant_id] = Scalar();
+            result[override_id] = Scalar();
             continue;
         }
 
         if (auto* l = literal->As<ast::BoolLiteralExpression>()) {
-            result[constant_id] = Scalar(l->value);
+            result[override_id] = Scalar(l->value);
             continue;
         }
 
@@ -274,32 +275,32 @@
             switch (l->suffix) {
                 case ast::IntLiteralExpression::Suffix::kNone:
                 case ast::IntLiteralExpression::Suffix::kI:
-                    result[constant_id] = Scalar(static_cast<int32_t>(l->value));
+                    result[override_id] = Scalar(static_cast<int32_t>(l->value));
                     continue;
                 case ast::IntLiteralExpression::Suffix::kU:
-                    result[constant_id] = Scalar(static_cast<uint32_t>(l->value));
+                    result[override_id] = Scalar(static_cast<uint32_t>(l->value));
                     continue;
             }
         }
 
         if (auto* l = literal->As<ast::FloatLiteralExpression>()) {
-            result[constant_id] = Scalar(static_cast<float>(l->value));
+            result[override_id] = Scalar(static_cast<float>(l->value));
             continue;
         }
 
-        result[constant_id] = Scalar();
+        result[override_id] = Scalar();
     }
 
     return result;
 }
 
-std::map<std::string, uint32_t> Inspector::GetConstantNameToIdMap() {
-    std::map<std::string, uint32_t> result;
+std::map<std::string, OverrideId> Inspector::GetNamedOverrideIds() {
+    std::map<std::string, OverrideId> result;
     for (auto* var : program_->AST().GlobalVariables()) {
         auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
         if (global && global->Declaration()->Is<ast::Override>()) {
             auto name = program_->Symbols().NameFor(var->symbol);
-            result[name] = global->ConstantId();
+            result[name] = global->OverrideId();
         }
     }
     return result;
@@ -644,7 +645,7 @@
     variables.push_back(stage_variable);
 }
 
-bool Inspector::ContainsBuiltin(ast::Builtin builtin,
+bool Inspector::ContainsBuiltin(ast::BuiltinValue builtin,
                                 const sem::Type* type,
                                 const ast::AttributeList& attributes) const {
     auto* unwrapped_type = type->UnwrapRef();
diff --git a/src/tint/inspector/inspector.h b/src/tint/inspector/inspector.h
index a5aee17..2690581 100644
--- a/src/tint/inspector/inspector.h
+++ b/src/tint/inspector/inspector.h
@@ -23,6 +23,8 @@
 #include <utility>
 #include <vector>
 
+#include "tint/override_id.h"
+
 #include "src/tint/inspector/entry_point.h"
 #include "src/tint/inspector/resource_binding.h"
 #include "src/tint/inspector/scalar.h"
@@ -53,11 +55,11 @@
     /// @returns vector of entry point information
     std::vector<EntryPoint> GetEntryPoints();
 
-    /// @returns map of const_id to initial value
-    std::map<uint32_t, Scalar> GetConstantIDs();
+    /// @returns map of override identifier to initial value
+    std::map<OverrideId, Scalar> GetOverrideDefaultValues();
 
     /// @returns map of module-constant name to pipeline constant ID
-    std::map<std::string, uint32_t> GetConstantNameToIdMap();
+    std::map<std::string, OverrideId> GetNamedOverrideIds();
 
     /// @param entry_point name of the entry point to get information about.
     /// @returns the total size of shared storage required by an entry point,
@@ -174,7 +176,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::Builtin builtin,
+    bool ContainsBuiltin(ast::BuiltinValue builtin,
                          const sem::Type* type,
                          const ast::AttributeList& attributes) const;
 
diff --git a/src/tint/inspector/inspector_test.cc b/src/tint/inspector/inspector_test.cc
index 2681f78..2bb862d 100644
--- a/src/tint/inspector/inspector_test.cc
+++ b/src/tint/inspector/inspector_test.cc
@@ -60,7 +60,7 @@
 class InspectorGetEntryPointInterpolateTest
     : public InspectorBuilder,
       public testing::TestWithParam<InspectorGetEntryPointInterpolateTestParams> {};
-class InspectorGetConstantIDsTest : public InspectorBuilder, public testing::Test {};
+class InspectorGetOverrideDefaultValuesTest : public InspectorBuilder, public testing::Test {};
 class InspectorGetConstantNameToIdMapTest : public InspectorBuilder, public testing::Test {};
 class InspectorGetStorageSizeTest : public InspectorBuilder, public testing::Test {};
 class InspectorGetResourceBindingsTest : public InspectorBuilder, public testing::Test {};
@@ -239,11 +239,11 @@
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
     ASSERT_EQ(1u, result.size());
-    uint32_t x, y, z;
-    std::tie(x, y, z) = result[0].workgroup_size();
-    EXPECT_EQ(8u, x);
-    EXPECT_EQ(2u, y);
-    EXPECT_EQ(1u, z);
+    auto workgroup_size = result[0].workgroup_size;
+    ASSERT_TRUE(workgroup_size.has_value());
+    EXPECT_EQ(8u, workgroup_size->x);
+    EXPECT_EQ(2u, workgroup_size->y);
+    EXPECT_EQ(1u, workgroup_size->z);
 }
 
 TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
@@ -258,11 +258,11 @@
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
     ASSERT_EQ(1u, result.size());
-    uint32_t x, y, z;
-    std::tie(x, y, z) = result[0].workgroup_size();
-    EXPECT_EQ(8u, x);
-    EXPECT_EQ(2u, y);
-    EXPECT_EQ(1u, z);
+    auto workgroup_size = result[0].workgroup_size;
+    ASSERT_TRUE(workgroup_size.has_value());
+    EXPECT_EQ(8u, workgroup_size->x);
+    EXPECT_EQ(2u, workgroup_size->y);
+    EXPECT_EQ(1u, workgroup_size->z);
 }
 
 TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
@@ -434,7 +434,7 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables) {
-    auto* in_var0 = Param("in_var0", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
+    auto* in_var0 = Param("in_var0", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)});
     auto* in_var1 = Param("in_var1", ty.f32(), {Location(0u)});
     Func("foo", {in_var0, in_var1}, ty.f32(),
          {
@@ -444,7 +444,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          {
-             Builtin(ast::Builtin::kFragDepth),
+             Builtin(ast::BuiltinValue::kFragDepth),
          });
     Inspector& inspector = Build();
 
@@ -605,8 +605,8 @@
     EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
 }
 
-TEST_F(InspectorGetEntryPointTest, OverridableConstantUnreferenced) {
-    AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideUnreferenced) {
+    Override("foo", ty.f32(), nullptr);
     MakeEmptyBodyFunction("ep_func", {
                                          Stage(ast::PipelineStage::kCompute),
                                          WorkgroupSize(1_i),
@@ -617,11 +617,11 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    EXPECT_EQ(0u, result[0].overridable_constants.size());
+    EXPECT_EQ(0u, result[0].overrides.size());
 }
 
-TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByEntryPoint) {
-    AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideReferencedByEntryPoint) {
+    Override("foo", ty.f32(), nullptr);
     MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
                                          {
                                              Stage(ast::PipelineStage::kCompute),
@@ -633,12 +633,12 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    ASSERT_EQ(1u, result[0].overridable_constants.size());
-    EXPECT_EQ("foo", result[0].overridable_constants[0].name);
+    ASSERT_EQ(1u, result[0].overrides.size());
+    EXPECT_EQ("foo", result[0].overrides[0].name);
 }
 
-TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByCallee) {
-    AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideReferencedByCallee) {
+    Override("foo", ty.f32(), nullptr);
     MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
     MakeCallerBodyFunction("ep_func", {"callee_func"},
                            {
@@ -651,13 +651,13 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    ASSERT_EQ(1u, result[0].overridable_constants.size());
-    EXPECT_EQ("foo", result[0].overridable_constants[0].name);
+    ASSERT_EQ(1u, result[0].overrides.size());
+    EXPECT_EQ("foo", result[0].overrides[0].name);
 }
 
-TEST_F(InspectorGetEntryPointTest, OverridableConstantSomeReferenced) {
-    AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
-    AddOverridableConstantWithID("bar", 2, ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideSomeReferenced) {
+    Override("foo", ty.f32(), nullptr, {Id(1)});
+    Override("bar", ty.f32(), nullptr, {Id(2)});
     MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
     MakeCallerBodyFunction("ep_func", {"callee_func"},
                            {
@@ -670,16 +670,16 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    ASSERT_EQ(1u, result[0].overridable_constants.size());
-    EXPECT_EQ("foo", result[0].overridable_constants[0].name);
-    EXPECT_EQ(1, result[0].overridable_constants[0].numeric_id);
+    ASSERT_EQ(1u, result[0].overrides.size());
+    EXPECT_EQ("foo", result[0].overrides[0].name);
+    EXPECT_EQ(1, result[0].overrides[0].id.value);
 }
 
-TEST_F(InspectorGetEntryPointTest, OverridableConstantTypes) {
-    AddOverridableConstantWithoutID("bool_var", ty.bool_(), nullptr);
-    AddOverridableConstantWithoutID("float_var", ty.f32(), nullptr);
-    AddOverridableConstantWithoutID("u32_var", ty.u32(), nullptr);
-    AddOverridableConstantWithoutID("i32_var", ty.i32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideTypes) {
+    Override("bool_var", ty.bool_(), nullptr);
+    Override("float_var", ty.f32(), nullptr);
+    Override("u32_var", ty.u32(), nullptr);
+    Override("i32_var", ty.i32(), nullptr);
 
     MakePlainGlobalReferenceBodyFunction("bool_func", "bool_var", ty.bool_(), {});
     MakePlainGlobalReferenceBodyFunction("float_func", "float_var", ty.f32(), {});
@@ -697,22 +697,19 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    ASSERT_EQ(4u, result[0].overridable_constants.size());
-    EXPECT_EQ("bool_var", result[0].overridable_constants[0].name);
-    EXPECT_EQ(inspector::OverridableConstant::Type::kBool, result[0].overridable_constants[0].type);
-    EXPECT_EQ("float_var", result[0].overridable_constants[1].name);
-    EXPECT_EQ(inspector::OverridableConstant::Type::kFloat32,
-              result[0].overridable_constants[1].type);
-    EXPECT_EQ("u32_var", result[0].overridable_constants[2].name);
-    EXPECT_EQ(inspector::OverridableConstant::Type::kUint32,
-              result[0].overridable_constants[2].type);
-    EXPECT_EQ("i32_var", result[0].overridable_constants[3].name);
-    EXPECT_EQ(inspector::OverridableConstant::Type::kInt32,
-              result[0].overridable_constants[3].type);
+    ASSERT_EQ(4u, result[0].overrides.size());
+    EXPECT_EQ("bool_var", result[0].overrides[0].name);
+    EXPECT_EQ(inspector::Override::Type::kBool, result[0].overrides[0].type);
+    EXPECT_EQ("float_var", result[0].overrides[1].name);
+    EXPECT_EQ(inspector::Override::Type::kFloat32, result[0].overrides[1].type);
+    EXPECT_EQ("u32_var", result[0].overrides[2].name);
+    EXPECT_EQ(inspector::Override::Type::kUint32, result[0].overrides[2].type);
+    EXPECT_EQ("i32_var", result[0].overrides[3].name);
+    EXPECT_EQ(inspector::Override::Type::kInt32, result[0].overrides[3].type);
 }
 
-TEST_F(InspectorGetEntryPointTest, OverridableConstantInitialized) {
-    AddOverridableConstantWithoutID("foo", ty.f32(), Expr(0_f));
+TEST_F(InspectorGetEntryPointTest, OverrideInitialized) {
+    Override("foo", ty.f32(), Expr(0_f));
     MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
                                          {
                                              Stage(ast::PipelineStage::kCompute),
@@ -724,13 +721,13 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    ASSERT_EQ(1u, result[0].overridable_constants.size());
-    EXPECT_EQ("foo", result[0].overridable_constants[0].name);
-    EXPECT_TRUE(result[0].overridable_constants[0].is_initialized);
+    ASSERT_EQ(1u, result[0].overrides.size());
+    EXPECT_EQ("foo", result[0].overrides[0].name);
+    EXPECT_TRUE(result[0].overrides[0].is_initialized);
 }
 
-TEST_F(InspectorGetEntryPointTest, OverridableConstantUninitialized) {
-    AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideUninitialized) {
+    Override("foo", ty.f32(), nullptr);
     MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
                                          {
                                              Stage(ast::PipelineStage::kCompute),
@@ -742,15 +739,15 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    ASSERT_EQ(1u, result[0].overridable_constants.size());
-    EXPECT_EQ("foo", result[0].overridable_constants[0].name);
+    ASSERT_EQ(1u, result[0].overrides.size());
+    EXPECT_EQ("foo", result[0].overrides[0].name);
 
-    EXPECT_FALSE(result[0].overridable_constants[0].is_initialized);
+    EXPECT_FALSE(result[0].overrides[0].is_initialized);
 }
 
-TEST_F(InspectorGetEntryPointTest, OverridableConstantNumericIDSpecified) {
-    AddOverridableConstantWithoutID("foo_no_id", ty.f32(), nullptr);
-    AddOverridableConstantWithID("foo_id", 1234, ty.f32(), nullptr);
+TEST_F(InspectorGetEntryPointTest, OverrideNumericIDSpecified) {
+    Override("foo_no_id", ty.f32(), nullptr);
+    Override("foo_id", ty.f32(), nullptr, {Id(1234)});
 
     MakePlainGlobalReferenceBodyFunction("no_id_func", "foo_no_id", ty.f32(), {});
     MakePlainGlobalReferenceBodyFunction("id_func", "foo_id", ty.f32(), {});
@@ -766,16 +763,16 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    ASSERT_EQ(2u, result[0].overridable_constants.size());
-    EXPECT_EQ("foo_no_id", result[0].overridable_constants[0].name);
-    EXPECT_EQ("foo_id", result[0].overridable_constants[1].name);
-    EXPECT_EQ(1234, result[0].overridable_constants[1].numeric_id);
+    ASSERT_EQ(2u, result[0].overrides.size());
+    EXPECT_EQ("foo_no_id", result[0].overrides[0].name);
+    EXPECT_EQ("foo_id", result[0].overrides[1].name);
+    EXPECT_EQ(1234, result[0].overrides[1].id.value);
 
-    EXPECT_FALSE(result[0].overridable_constants[0].is_numeric_id_specified);
-    EXPECT_TRUE(result[0].overridable_constants[1].is_numeric_id_specified);
+    EXPECT_FALSE(result[0].overrides[0].is_id_specified);
+    EXPECT_TRUE(result[0].overrides[1].is_id_specified);
 }
 
-TEST_F(InspectorGetEntryPointTest, NonOverridableConstantSkipped) {
+TEST_F(InspectorGetEntryPointTest, NonOverrideSkipped) {
     auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
     AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
     MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
@@ -789,7 +786,7 @@
     auto result = inspector.GetEntryPoints();
 
     ASSERT_EQ(1u, result.size());
-    EXPECT_EQ(0u, result[0].overridable_constants.size());
+    EXPECT_EQ(0u, result[0].overrides.size());
 }
 
 TEST_F(InspectorGetEntryPointTest, BuiltinNotReferenced) {
@@ -811,7 +808,7 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, InputSampleMaskSimpleReferenced) {
-    auto* in_var = Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
+    auto* in_var = Param("in_var", ty.u32(), {Builtin(ast::BuiltinValue::kSampleMask)});
     Func("ep_func", {in_var}, ty.void_(),
          {
              Return(),
@@ -830,7 +827,8 @@
 
 TEST_F(InspectorGetEntryPointTest, InputSampleMaskStructReferenced) {
     ast::StructMemberList members;
-    members.push_back(Member("inner_position", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}));
+    members.push_back(
+        Member("inner_position", ty.u32(), {Builtin(ast::BuiltinValue::kSampleMask)}));
     Structure("in_struct", members);
 
     Func("ep_func",
@@ -856,7 +854,7 @@
 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskSimpleReferenced) {
     Func("ep_func",
          {
-             Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}),
+             Param("in_var", ty.u32(), {Builtin(ast::BuiltinValue::kSampleMask)}),
          },
          ty.u32(),
          {
@@ -865,7 +863,7 @@
          {
              Stage(ast::PipelineStage::kFragment),
          },
-         {Builtin(ast::Builtin::kSampleMask)});
+         {Builtin(ast::BuiltinValue::kSampleMask)});
 
     Inspector& inspector = Build();
 
@@ -878,7 +876,7 @@
 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskStructReferenced) {
     Structure("out_struct",
               {
-                  Member("inner_sample_mask", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}),
+                  Member("inner_sample_mask", ty.u32(), {Builtin(ast::BuiltinValue::kSampleMask)}),
               });
 
     Func("ep_func", {}, ty.type_name("out_struct"),
@@ -901,7 +899,7 @@
 TEST_F(InspectorGetEntryPointTest, InputPositionSimpleReferenced) {
     Func("ep_func",
          {
-             Param("in_var", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+             Param("in_var", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)}),
          },
          ty.void_(),
          {
@@ -922,7 +920,7 @@
 TEST_F(InspectorGetEntryPointTest, InputPositionStructReferenced) {
     Structure("in_struct",
               {
-                  Member("inner_position", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                  Member("inner_position", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)}),
               });
 
     Func("ep_func",
@@ -948,7 +946,7 @@
 TEST_F(InspectorGetEntryPointTest, FrontFacingSimpleReferenced) {
     Func("ep_func",
          {
-             Param("in_var", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)}),
+             Param("in_var", ty.bool_(), {Builtin(ast::BuiltinValue::kFrontFacing)}),
          },
          ty.void_(),
          {
@@ -969,7 +967,7 @@
 TEST_F(InspectorGetEntryPointTest, FrontFacingStructReferenced) {
     Structure("in_struct",
               {
-                  Member("inner_position", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)}),
+                  Member("inner_position", ty.bool_(), {Builtin(ast::BuiltinValue::kFrontFacing)}),
               });
 
     Func("ep_func",
@@ -995,7 +993,7 @@
 TEST_F(InspectorGetEntryPointTest, SampleIndexSimpleReferenced) {
     Func("ep_func",
          {
-             Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)}),
+             Param("in_var", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)}),
          },
          ty.void_(),
          {
@@ -1016,7 +1014,7 @@
 TEST_F(InspectorGetEntryPointTest, SampleIndexStructReferenced) {
     Structure("in_struct",
               {
-                  Member("inner_position", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)}),
+                  Member("inner_position", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)}),
               });
 
     Func("ep_func",
@@ -1042,7 +1040,7 @@
 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsSimpleReferenced) {
     Func("ep_func",
          {
-             Param("in_var", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)}),
+             Param("in_var", ty.vec3<u32>(), {Builtin(ast::BuiltinValue::kNumWorkgroups)}),
          },
          ty.void_(),
          {
@@ -1059,10 +1057,10 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsStructReferenced) {
-    Structure("in_struct",
-              {
-                  Member("inner_position", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)}),
-              });
+    Structure("in_struct", {
+                               Member("inner_position", ty.vec3<u32>(),
+                                      {Builtin(ast::BuiltinValue::kNumWorkgroups)}),
+                           });
 
     Func("ep_func",
          {
@@ -1171,127 +1169,127 @@
             ast::InterpolationType::kFlat, ast::InterpolationSampling::kNone,
             InterpolationType::kFlat, InterpolationSampling::kNone}));
 
-TEST_F(InspectorGetConstantIDsTest, Bool) {
-    AddOverridableConstantWithID("foo", 1, ty.bool_(), nullptr);
-    AddOverridableConstantWithID("bar", 20, ty.bool_(), Expr(true));
-    AddOverridableConstantWithID("baz", 300, ty.bool_(), Expr(false));
+TEST_F(InspectorGetOverrideDefaultValuesTest, Bool) {
+    Override("foo", ty.bool_(), nullptr, {Id(1)});
+    Override("bar", ty.bool_(), Expr(true), {Id(20)});
+    Override("baz", ty.bool_(), Expr(false), {Id(300)});
 
     Inspector& inspector = Build();
 
-    auto result = inspector.GetConstantIDs();
+    auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(3u, result.size());
 
-    ASSERT_TRUE(result.find(1) != result.end());
-    EXPECT_TRUE(result[1].IsNull());
+    ASSERT_TRUE(result.find(OverrideId{1}) != result.end());
+    EXPECT_TRUE(result[OverrideId{1}].IsNull());
 
-    ASSERT_TRUE(result.find(20) != result.end());
-    EXPECT_TRUE(result[20].IsBool());
-    EXPECT_TRUE(result[20].AsBool());
+    ASSERT_TRUE(result.find(OverrideId{20}) != result.end());
+    EXPECT_TRUE(result[OverrideId{20}].IsBool());
+    EXPECT_TRUE(result[OverrideId{20}].AsBool());
 
-    ASSERT_TRUE(result.find(300) != result.end());
-    EXPECT_TRUE(result[300].IsBool());
-    EXPECT_FALSE(result[300].AsBool());
+    ASSERT_TRUE(result.find(OverrideId{300}) != result.end());
+    EXPECT_TRUE(result[OverrideId{300}].IsBool());
+    EXPECT_FALSE(result[OverrideId{300}].AsBool());
 }
 
-TEST_F(InspectorGetConstantIDsTest, U32) {
-    AddOverridableConstantWithID("foo", 1, ty.u32(), nullptr);
-    AddOverridableConstantWithID("bar", 20, ty.u32(), Expr(42_u));
+TEST_F(InspectorGetOverrideDefaultValuesTest, U32) {
+    Override("foo", ty.u32(), nullptr, {Id(1)});
+    Override("bar", ty.u32(), Expr(42_u), {Id(20)});
 
     Inspector& inspector = Build();
 
-    auto result = inspector.GetConstantIDs();
+    auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(2u, result.size());
 
-    ASSERT_TRUE(result.find(1) != result.end());
-    EXPECT_TRUE(result[1].IsNull());
+    ASSERT_TRUE(result.find(OverrideId{1}) != result.end());
+    EXPECT_TRUE(result[OverrideId{1}].IsNull());
 
-    ASSERT_TRUE(result.find(20) != result.end());
-    EXPECT_TRUE(result[20].IsU32());
-    EXPECT_EQ(42u, result[20].AsU32());
+    ASSERT_TRUE(result.find(OverrideId{20}) != result.end());
+    EXPECT_TRUE(result[OverrideId{20}].IsU32());
+    EXPECT_EQ(42u, result[OverrideId{20}].AsU32());
 }
 
-TEST_F(InspectorGetConstantIDsTest, I32) {
-    AddOverridableConstantWithID("foo", 1, ty.i32(), nullptr);
-    AddOverridableConstantWithID("bar", 20, ty.i32(), Expr(-42_i));
-    AddOverridableConstantWithID("baz", 300, ty.i32(), Expr(42_i));
+TEST_F(InspectorGetOverrideDefaultValuesTest, I32) {
+    Override("foo", ty.i32(), nullptr, {Id(1)});
+    Override("bar", ty.i32(), Expr(-42_i), {Id(20)});
+    Override("baz", ty.i32(), Expr(42_i), {Id(300)});
 
     Inspector& inspector = Build();
 
-    auto result = inspector.GetConstantIDs();
+    auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(3u, result.size());
 
-    ASSERT_TRUE(result.find(1) != result.end());
-    EXPECT_TRUE(result[1].IsNull());
+    ASSERT_TRUE(result.find(OverrideId{1}) != result.end());
+    EXPECT_TRUE(result[OverrideId{1}].IsNull());
 
-    ASSERT_TRUE(result.find(20) != result.end());
-    EXPECT_TRUE(result[20].IsI32());
-    EXPECT_EQ(-42, result[20].AsI32());
+    ASSERT_TRUE(result.find(OverrideId{20}) != result.end());
+    EXPECT_TRUE(result[OverrideId{20}].IsI32());
+    EXPECT_EQ(-42, result[OverrideId{20}].AsI32());
 
-    ASSERT_TRUE(result.find(300) != result.end());
-    EXPECT_TRUE(result[300].IsI32());
-    EXPECT_EQ(42, result[300].AsI32());
+    ASSERT_TRUE(result.find(OverrideId{300}) != result.end());
+    EXPECT_TRUE(result[OverrideId{300}].IsI32());
+    EXPECT_EQ(42, result[OverrideId{300}].AsI32());
 }
 
-TEST_F(InspectorGetConstantIDsTest, Float) {
-    AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
-    AddOverridableConstantWithID("bar", 20, ty.f32(), Expr(0_f));
-    AddOverridableConstantWithID("baz", 300, ty.f32(), Expr(-10_f));
-    AddOverridableConstantWithID("x", 4000, ty.f32(), Expr(15_f));
+TEST_F(InspectorGetOverrideDefaultValuesTest, Float) {
+    Override("foo", ty.f32(), nullptr, {Id(1)});
+    Override("bar", ty.f32(), Expr(0_f), {Id(20)});
+    Override("baz", ty.f32(), Expr(-10_f), {Id(300)});
+    Override("x", ty.f32(), Expr(15_f), {Id(4000)});
 
     Inspector& inspector = Build();
 
-    auto result = inspector.GetConstantIDs();
+    auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(4u, result.size());
 
-    ASSERT_TRUE(result.find(1) != result.end());
-    EXPECT_TRUE(result[1].IsNull());
+    ASSERT_TRUE(result.find(OverrideId{1}) != result.end());
+    EXPECT_TRUE(result[OverrideId{1}].IsNull());
 
-    ASSERT_TRUE(result.find(20) != result.end());
-    EXPECT_TRUE(result[20].IsFloat());
-    EXPECT_FLOAT_EQ(0.0f, result[20].AsFloat());
+    ASSERT_TRUE(result.find(OverrideId{20}) != result.end());
+    EXPECT_TRUE(result[OverrideId{20}].IsFloat());
+    EXPECT_FLOAT_EQ(0.0f, result[OverrideId{20}].AsFloat());
 
-    ASSERT_TRUE(result.find(300) != result.end());
-    EXPECT_TRUE(result[300].IsFloat());
-    EXPECT_FLOAT_EQ(-10.0f, result[300].AsFloat());
+    ASSERT_TRUE(result.find(OverrideId{300}) != result.end());
+    EXPECT_TRUE(result[OverrideId{300}].IsFloat());
+    EXPECT_FLOAT_EQ(-10.0f, result[OverrideId{300}].AsFloat());
 
-    ASSERT_TRUE(result.find(4000) != result.end());
-    EXPECT_TRUE(result[4000].IsFloat());
-    EXPECT_FLOAT_EQ(15.0f, result[4000].AsFloat());
+    ASSERT_TRUE(result.find(OverrideId{4000}) != result.end());
+    EXPECT_TRUE(result[OverrideId{4000}].IsFloat());
+    EXPECT_FLOAT_EQ(15.0f, result[OverrideId{4000}].AsFloat());
 }
 
 TEST_F(InspectorGetConstantNameToIdMapTest, WithAndWithoutIds) {
-    AddOverridableConstantWithID("v1", 1, ty.f32(), nullptr);
-    AddOverridableConstantWithID("v20", 20, ty.f32(), nullptr);
-    AddOverridableConstantWithID("v300", 300, ty.f32(), nullptr);
-    auto* a = AddOverridableConstantWithoutID("a", ty.f32(), nullptr);
-    auto* b = AddOverridableConstantWithoutID("b", ty.f32(), nullptr);
-    auto* c = AddOverridableConstantWithoutID("c", ty.f32(), nullptr);
+    Override("v1", ty.f32(), nullptr, {Id(1)});
+    Override("v20", ty.f32(), nullptr, {Id(20)});
+    Override("v300", ty.f32(), nullptr, {Id(300)});
+    auto* a = Override("a", ty.f32(), nullptr);
+    auto* b = Override("b", ty.f32(), nullptr);
+    auto* c = Override("c", ty.f32(), nullptr);
 
     Inspector& inspector = Build();
 
-    auto result = inspector.GetConstantNameToIdMap();
+    auto result = inspector.GetNamedOverrideIds();
     ASSERT_EQ(6u, result.size());
 
     ASSERT_TRUE(result.count("v1"));
-    EXPECT_EQ(result["v1"], 1u);
+    EXPECT_EQ(result["v1"].value, 1u);
 
     ASSERT_TRUE(result.count("v20"));
-    EXPECT_EQ(result["v20"], 20u);
+    EXPECT_EQ(result["v20"].value, 20u);
 
     ASSERT_TRUE(result.count("v300"));
-    EXPECT_EQ(result["v300"], 300u);
+    EXPECT_EQ(result["v300"].value, 300u);
 
     ASSERT_TRUE(result.count("a"));
     ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(a));
-    EXPECT_EQ(result["a"], program_->Sem().Get<sem::GlobalVariable>(a)->ConstantId());
+    EXPECT_EQ(result["a"], program_->Sem().Get<sem::GlobalVariable>(a)->OverrideId());
 
     ASSERT_TRUE(result.count("b"));
     ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(b));
-    EXPECT_EQ(result["b"], program_->Sem().Get<sem::GlobalVariable>(b)->ConstantId());
+    EXPECT_EQ(result["b"], program_->Sem().Get<sem::GlobalVariable>(b)->OverrideId());
 
     ASSERT_TRUE(result.count("c"));
     ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(c));
-    EXPECT_EQ(result["c"], program_->Sem().Get<sem::GlobalVariable>(c)->ConstantId());
+    EXPECT_EQ(result["c"], program_->Sem().Get<sem::GlobalVariable>(c)->OverrideId());
 }
 
 TEST_F(InspectorGetStorageSizeTest, Empty) {
diff --git a/src/tint/inspector/resource_binding.cc b/src/tint/inspector/resource_binding.cc
index 3efb59e..6434ac2 100644
--- a/src/tint/inspector/resource_binding.cc
+++ b/src/tint/inspector/resource_binding.cc
@@ -104,7 +104,7 @@
             return ResourceBinding::TexelFormat::kRgba32Sint;
         case ast::TexelFormat::kRgba32Float:
             return ResourceBinding::TexelFormat::kRgba32Float;
-        case ast::TexelFormat::kNone:
+        case ast::TexelFormat::kInvalid:
             return ResourceBinding::TexelFormat::kNone;
     }
     return ResourceBinding::TexelFormat::kNone;
diff --git a/src/tint/inspector/test_inspector_builder.h b/src/tint/inspector/test_inspector_builder.h
index 391e1a1..a3ccb13 100644
--- a/src/tint/inspector/test_inspector_builder.h
+++ b/src/tint/inspector/test_inspector_builder.h
@@ -92,31 +92,6 @@
         std::vector<std::tuple<std::string, std::string>> inout_vars,
         ast::AttributeList attributes);
 
-    /// Add a pipeline constant to the global variables, with a specific ID.
-    /// @param name name of the variable to add
-    /// @param id id number for the constant id
-    /// @param type type of the variable
-    /// @param constructor val to initialize the constant with, if NULL no
-    ///             constructor will be added.
-    /// @returns the constant that was created
-    const ast::Variable* AddOverridableConstantWithID(std::string name,
-                                                      uint32_t id,
-                                                      const ast::Type* type,
-                                                      const ast::Expression* constructor) {
-        return Override(name, type, constructor, {Id(id)});
-    }
-
-    /// Add a pipeline constant to the global variables, without a specific ID.
-    /// @param name name of the variable to add
-    /// @param type type of the variable
-    /// @param constructor val to initialize the constant with, if NULL no
-    ///             constructor will be added.
-    /// @returns the constant that was created
-    const ast::Variable* AddOverridableConstantWithoutID(std::string name,
-                                                         const ast::Type* type,
-                                                         const ast::Expression* constructor) {
-        return Override(name, type, constructor);
-    }
 
     /// Generates a function that references module-scoped, plain-typed constant
     /// or variable.
diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def
index c971af5..072d38a 100644
--- a/src/tint/intrinsics.def
+++ b/src/tint/intrinsics.def
@@ -23,14 +23,45 @@
 // Enumerators                                                                //
 ////////////////////////////////////////////////////////////////////////////////
 
+// https://gpuweb.github.io/gpuweb/wgsl/#builtin-values
+enum builtin_value {
+  position
+  vertex_index
+  instance_index
+  front_facing
+  frag_depth
+  local_invocation_id
+  local_invocation_index
+  global_invocation_id
+  workgroup_id
+  num_workgroups
+  sample_index
+  sample_mask
+  @internal point_size
+}
+
+// https://gpuweb.github.io/gpuweb/wgsl/#extension
+enum extension {
+  // WGSL Extension "f16"
+  f16
+  // An extension for the experimental feature "chromium_experimental_dp4a".
+  // See crbug.com/tint/1497 for more details
+  chromium_experimental_dp4a
+  // A Chromium-specific extension for disabling uniformity analysis.
+  chromium_disable_uniformity_analysis
+}
+
 // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
 enum storage_class {
+  @internal none
   function
   private
   workgroup
   uniform
   storage
   @internal handle
+  @internal in
+  @internal out
 }
 
 // https://gpuweb.github.io/gpuweb/wgsl/#memory-access-mode
@@ -135,6 +166,8 @@
 match scalar_no_u32: f32 | f16 | i32 | bool
 match scalar_no_bool: f32 | f16 | i32 | u32
 match fia_fi32_f16: fa | ia | f32 | i32 | f16
+match fia_fiu32: fa | ia | f32 | i32 | u32
+match fa_f32: fa | f32
 match fa_f32_f16: fa | f32 | f16
 match ia_iu32: ia | i32 | u32
 match fiu32_f16: f32 | i32 | u32 | f16
@@ -370,14 +403,14 @@
 fn asinh<N: num>(vec<N, f32>) -> vec<N, f32>
 fn atan(f32) -> f32
 fn atan<N: num>(vec<N, f32>) -> vec<N, f32>
-fn atan2(f32, f32) -> f32
-fn atan2<N: num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32>
+@const fn atan2<T: fa_f32>(T, T) -> T
+@const fn atan2<N: num, T: fa_f32>(vec<N, T>, vec<N, T>) -> vec<N, T>
 fn atanh(f32) -> f32
 fn atanh<N: num>(vec<N, f32>) -> vec<N, f32>
 fn ceil(f32) -> f32
 fn ceil<N: num>(vec<N, f32>) -> vec<N, f32>
-fn clamp<T: fiu32>(T, T, T) -> T
-fn clamp<N: num, T: fiu32>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@const fn clamp<T: fia_fiu32>(T, T, T) -> T
+@const fn clamp<N: num, T: fia_fiu32>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
 fn cos(f32) -> f32
 fn cos<N: num>(vec<N, f32>) -> vec<N, f32>
 fn cosh(f32) -> f32
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index c6b163f..61954ee 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -19,6 +19,8 @@
 #include <unordered_set>
 #include <utility>
 
+#include "tint/override_id.h"
+
 #include "src/tint/ast/alias.h"
 #include "src/tint/ast/array.h"
 #include "src/tint/ast/assignment_statement.h"
@@ -2518,14 +2520,14 @@
     /// @param source the source information
     /// @param builtin the builtin value
     /// @returns the builtin attribute pointer
-    const ast::BuiltinAttribute* Builtin(const Source& source, ast::Builtin builtin) {
+    const ast::BuiltinAttribute* Builtin(const Source& source, ast::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::Builtin builtin) {
+    const ast::BuiltinAttribute* Builtin(ast::BuiltinValue builtin) {
         return create<ast::BuiltinAttribute>(source_, builtin);
     }
 
@@ -2592,11 +2594,24 @@
     /// @param source the source information
     /// @param id the id value
     /// @returns the override attribute pointer
+    const ast::IdAttribute* Id(const Source& source, OverrideId id) {
+        return create<ast::IdAttribute>(source, id.value);
+    }
+
+    /// Creates an ast::IdAttribute with an override identifier
+    /// @param id the optional id value
+    /// @returns the override attribute pointer
+    const ast::IdAttribute* Id(OverrideId id) { return Id(source_, id); }
+
+    /// Creates an ast::IdAttribute
+    /// @param source the source information
+    /// @param id the id value
+    /// @returns the override attribute pointer
     const ast::IdAttribute* Id(const Source& source, uint32_t id) {
         return create<ast::IdAttribute>(source, id);
     }
 
-    /// Creates an ast::IdAttribute with a constant ID
+    /// Creates an ast::IdAttribute with an override identifier
     /// @param id the optional id value
     /// @returns the override attribute pointer
     const ast::IdAttribute* Id(uint32_t id) { return Id(source_, id); }
diff --git a/src/tint/reader/spirv/enum_converter.cc b/src/tint/reader/spirv/enum_converter.cc
index 6f61ee6..8791670 100644
--- a/src/tint/reader/spirv/enum_converter.cc
+++ b/src/tint/reader/spirv/enum_converter.cc
@@ -62,38 +62,38 @@
     return ast::StorageClass::kInvalid;
 }
 
-ast::Builtin EnumConverter::ToBuiltin(SpvBuiltIn b) {
+ast::BuiltinValue EnumConverter::ToBuiltin(SpvBuiltIn b) {
     switch (b) {
         case SpvBuiltInPosition:
-            return ast::Builtin::kPosition;
+            return ast::BuiltinValue::kPosition;
         case SpvBuiltInVertexIndex:
-            return ast::Builtin::kVertexIndex;
+            return ast::BuiltinValue::kVertexIndex;
         case SpvBuiltInInstanceIndex:
-            return ast::Builtin::kInstanceIndex;
+            return ast::BuiltinValue::kInstanceIndex;
         case SpvBuiltInFrontFacing:
-            return ast::Builtin::kFrontFacing;
+            return ast::BuiltinValue::kFrontFacing;
         case SpvBuiltInFragCoord:
-            return ast::Builtin::kPosition;
+            return ast::BuiltinValue::kPosition;
         case SpvBuiltInFragDepth:
-            return ast::Builtin::kFragDepth;
+            return ast::BuiltinValue::kFragDepth;
         case SpvBuiltInLocalInvocationId:
-            return ast::Builtin::kLocalInvocationId;
+            return ast::BuiltinValue::kLocalInvocationId;
         case SpvBuiltInLocalInvocationIndex:
-            return ast::Builtin::kLocalInvocationIndex;
+            return ast::BuiltinValue::kLocalInvocationIndex;
         case SpvBuiltInGlobalInvocationId:
-            return ast::Builtin::kGlobalInvocationId;
+            return ast::BuiltinValue::kGlobalInvocationId;
         case SpvBuiltInWorkgroupId:
-            return ast::Builtin::kWorkgroupId;
+            return ast::BuiltinValue::kWorkgroupId;
         case SpvBuiltInSampleId:
-            return ast::Builtin::kSampleIndex;
+            return ast::BuiltinValue::kSampleIndex;
         case SpvBuiltInSampleMask:
-            return ast::Builtin::kSampleMask;
+            return ast::BuiltinValue::kSampleMask;
         default:
             break;
     }
 
     Fail() << "unknown SPIR-V builtin: " << uint32_t(b);
-    return ast::Builtin::kNone;
+    return ast::BuiltinValue::kInvalid;
 }
 
 ast::TextureDimension EnumConverter::ToDim(SpvDim dim, bool arrayed) {
@@ -129,7 +129,7 @@
 ast::TexelFormat EnumConverter::ToTexelFormat(SpvImageFormat fmt) {
     switch (fmt) {
         case SpvImageFormatUnknown:
-            return ast::TexelFormat::kNone;
+            return ast::TexelFormat::kInvalid;
 
         // 8 bit channels
         case SpvImageFormatRgba8:
@@ -172,7 +172,7 @@
             break;
     }
     Fail() << "invalid image format: " << int(fmt);
-    return ast::TexelFormat::kNone;
+    return ast::TexelFormat::kInvalid;
 }
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/enum_converter.h b/src/tint/reader/spirv/enum_converter.h
index ac86f71..fc3ad83 100644
--- a/src/tint/reader/spirv/enum_converter.h
+++ b/src/tint/reader/spirv/enum_converter.h
@@ -16,7 +16,7 @@
 #define SRC_TINT_READER_SPIRV_ENUM_CONVERTER_H_
 
 #include "spirv/unified1/spirv.h"
-#include "src/tint/ast/builtin.h"
+#include "src/tint/ast/builtin_value.h"
 #include "src/tint/ast/pipeline_stage.h"
 #include "src/tint/ast/storage_class.h"
 #include "src/tint/reader/spirv/fail_stream.h"
@@ -49,7 +49,7 @@
     /// On failure, logs an error and returns kNone
     /// @param b the SPIR-V builtin
     /// @returns a Tint AST builtin
-    ast::Builtin ToBuiltin(SpvBuiltIn b);
+    ast::BuiltinValue ToBuiltin(SpvBuiltIn 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 a7d8de1..95a6264 100644
--- a/src/tint/reader/spirv/enum_converter_test.cc
+++ b/src/tint/reader/spirv/enum_converter_test.cc
@@ -144,7 +144,7 @@
 struct BuiltinCase {
     SpvBuiltIn builtin;
     bool expect_success;
-    ast::Builtin expected;
+    ast::BuiltinValue expected;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinCase bc) {
     out << "BuiltinCase{ SpvBuiltIn:" << int(bc.builtin)
@@ -184,30 +184,30 @@
     EnumConverterGood_Input,
     SpvBuiltinTest,
     testing::Values(
-        BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
-        BuiltinCase{SpvBuiltInInstanceIndex, true, ast::Builtin::kInstanceIndex},
-        BuiltinCase{SpvBuiltInFrontFacing, true, ast::Builtin::kFrontFacing},
-        BuiltinCase{SpvBuiltInFragCoord, true, ast::Builtin::kPosition},
-        BuiltinCase{SpvBuiltInLocalInvocationId, true, ast::Builtin::kLocalInvocationId},
-        BuiltinCase{SpvBuiltInLocalInvocationIndex, true, ast::Builtin::kLocalInvocationIndex},
-        BuiltinCase{SpvBuiltInGlobalInvocationId, true, ast::Builtin::kGlobalInvocationId},
-        BuiltinCase{SpvBuiltInWorkgroupId, true, ast::Builtin::kWorkgroupId},
-        BuiltinCase{SpvBuiltInSampleId, true, ast::Builtin::kSampleIndex},
-        BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::kSampleMask}));
+        BuiltinCase{SpvBuiltInPosition, true, ast::BuiltinValue::kPosition},
+        BuiltinCase{SpvBuiltInInstanceIndex, true, ast::BuiltinValue::kInstanceIndex},
+        BuiltinCase{SpvBuiltInFrontFacing, true, ast::BuiltinValue::kFrontFacing},
+        BuiltinCase{SpvBuiltInFragCoord, true, ast::BuiltinValue::kPosition},
+        BuiltinCase{SpvBuiltInLocalInvocationId, true, ast::BuiltinValue::kLocalInvocationId},
+        BuiltinCase{SpvBuiltInLocalInvocationIndex, true, ast::BuiltinValue::kLocalInvocationIndex},
+        BuiltinCase{SpvBuiltInGlobalInvocationId, true, ast::BuiltinValue::kGlobalInvocationId},
+        BuiltinCase{SpvBuiltInWorkgroupId, true, ast::BuiltinValue::kWorkgroupId},
+        BuiltinCase{SpvBuiltInSampleId, true, ast::BuiltinValue::kSampleIndex},
+        BuiltinCase{SpvBuiltInSampleMask, true, ast::BuiltinValue::kSampleMask}));
 
 INSTANTIATE_TEST_SUITE_P(
     EnumConverterGood_Output,
     SpvBuiltinTest,
-    testing::Values(BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
-                    BuiltinCase{SpvBuiltInFragDepth, true, ast::Builtin::kFragDepth},
-                    BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::kSampleMask}));
+    testing::Values(BuiltinCase{SpvBuiltInPosition, true, ast::BuiltinValue::kPosition},
+                    BuiltinCase{SpvBuiltInFragDepth, true, ast::BuiltinValue::kFragDepth},
+                    BuiltinCase{SpvBuiltInSampleMask, true, ast::BuiltinValue::kSampleMask}));
 
 INSTANTIATE_TEST_SUITE_P(
     EnumConverterBad,
     SpvBuiltinTest,
-    testing::Values(BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
-                    BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
-                    BuiltinCase{SpvBuiltInNumWorkgroups, false, ast::Builtin::kNone}));
+    testing::Values(BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::BuiltinValue::kInvalid},
+                    BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::BuiltinValue::kInvalid},
+                    BuiltinCase{SpvBuiltInNumWorkgroups, false, ast::BuiltinValue::kInvalid}));
 
 // Dim
 
@@ -326,7 +326,7 @@
     SpvImageFormatTest,
     testing::Values(
         // Unknown.  This is used for sampled images.
-        TexelFormatCase{SpvImageFormatUnknown, true, ast::TexelFormat::kNone},
+        TexelFormatCase{SpvImageFormatUnknown, true, ast::TexelFormat::kInvalid},
         // 8 bit channels
         TexelFormatCase{SpvImageFormatRgba8, true, ast::TexelFormat::kRgba8Unorm},
         TexelFormatCase{SpvImageFormatRgba8Snorm, true, ast::TexelFormat::kRgba8Snorm},
@@ -355,23 +355,23 @@
     SpvImageFormatTest,
     testing::Values(
         // Scanning in order from the SPIR-V spec.
-        TexelFormatCase{SpvImageFormatRg16f, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatR11fG11fB10f, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatR16f, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRgb10A2, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRg16, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRg8, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatR16, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatR8, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRgba16Snorm, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRg16Snorm, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRg8Snorm, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRg16i, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRg8i, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatR8i, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRgb10a2ui, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRg16ui, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatRg8ui, false, ast::TexelFormat::kNone}));
+        TexelFormatCase{SpvImageFormatRg16f, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatR11fG11fB10f, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatR16f, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRgb10A2, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRg16, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRg8, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatR16, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatR8, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRgba16Snorm, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRg16Snorm, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRg8Snorm, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRg16i, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRg8i, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatR8i, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRgb10a2ui, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRg16ui, false, ast::TexelFormat::kInvalid},
+        TexelFormatCase{SpvImageFormatRg8ui, false, ast::TexelFormat::kInvalid}));
 
 }  // namespace
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index 7c10f89..06f9ecb 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -20,8 +20,8 @@
 #include "src/tint/ast/assignment_statement.h"
 #include "src/tint/ast/bitcast_expression.h"
 #include "src/tint/ast/break_statement.h"
-#include "src/tint/ast/builtin.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"
@@ -746,7 +746,7 @@
 /// @returns true if the decorations include a SampleMask builtin
 bool HasBuiltinSampleMask(const ast::AttributeList& decos) {
     if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(decos)) {
-        return builtin->builtin == ast::Builtin::kSampleMask;
+        return builtin->builtin == ast::BuiltinValue::kSampleMask;
     }
     return false;
 }
@@ -1332,7 +1332,7 @@
                 // a gl_Position variable.  Substitute the type.
                 const Type* param_type = ty_.Vector(ty_.F32(), 4);
                 ast::AttributeList out_decos{
-                    create<ast::BuiltinAttribute>(source, ast::Builtin::kPosition)};
+                    create<ast::BuiltinAttribute>(source, ast::BuiltinValue::kPosition)};
 
                 const auto var_name = namer_.GetName(var_id);
                 return_members.push_back(
diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc
index 76ade39..18d5761 100644
--- a/src/tint/reader/spirv/parser_impl.cc
+++ b/src/tint/reader/spirv/parser_impl.cc
@@ -1676,7 +1676,7 @@
                     break;
             }
             auto ast_builtin = enum_converter_.ToBuiltin(spv_builtin);
-            if (ast_builtin == ast::Builtin::kNone) {
+            if (ast_builtin == ast::BuiltinValue::kInvalid) {
                 // A diagnostic has already been emitted.
                 return false;
             }
@@ -2476,7 +2476,7 @@
         } else {
             const auto access = ast::Access::kWrite;
             const auto format = enum_converter_.ToTexelFormat(image_type->format());
-            if (format == ast::TexelFormat::kNone) {
+            if (format == ast::TexelFormat::kInvalid) {
                 return nullptr;
             }
             ast_store_type = ty_.StorageTexture(dim, format, access);
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index 9830621..3adab59 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -70,46 +70,6 @@
 const char kWriteAccess[] = "write";
 const char kReadWriteAccess[] = "read_write";
 
-ast::Builtin ident_to_builtin(std::string_view str) {
-    if (str == "position") {
-        return ast::Builtin::kPosition;
-    }
-    if (str == "vertex_index") {
-        return ast::Builtin::kVertexIndex;
-    }
-    if (str == "instance_index") {
-        return ast::Builtin::kInstanceIndex;
-    }
-    if (str == "front_facing") {
-        return ast::Builtin::kFrontFacing;
-    }
-    if (str == "frag_depth") {
-        return ast::Builtin::kFragDepth;
-    }
-    if (str == "local_invocation_id") {
-        return ast::Builtin::kLocalInvocationId;
-    }
-    if (str == "local_invocation_idx" || str == "local_invocation_index") {
-        return ast::Builtin::kLocalInvocationIndex;
-    }
-    if (str == "global_invocation_id") {
-        return ast::Builtin::kGlobalInvocationId;
-    }
-    if (str == "workgroup_id") {
-        return ast::Builtin::kWorkgroupId;
-    }
-    if (str == "num_workgroups") {
-        return ast::Builtin::kNumWorkgroups;
-    }
-    if (str == "sample_index") {
-        return ast::Builtin::kSampleIndex;
-    }
-    if (str == "sample_mask") {
-        return ast::Builtin::kSampleMask;
-    }
-    return ast::Builtin::kNone;
-}
-
 const char kBindingAttribute[] = "binding";
 const char kBuiltinAttribute[] = "builtin";
 const char kGroupAttribute[] = "group";
@@ -288,7 +248,11 @@
         next_token_idx_++;
     }
     last_source_idx_ = next_token_idx_;
-    return tokens_[next_token_idx_++];
+
+    if (!tokens_[next_token_idx_].IsEof() && !tokens_[next_token_idx_].IsError()) {
+        next_token_idx_++;
+    }
+    return tokens_[last_source_idx_];
 }
 
 const Token& ParserImpl::peek(size_t idx) {
@@ -303,6 +267,9 @@
         }
         idx++;
     }
+    if (next_token_idx_ + idx >= tokens_.size()) {
+        return tokens_[tokens_.size() - 1];
+    }
 
     return tokens_[next_token_idx_ + idx];
 }
@@ -418,7 +385,7 @@
         }
 
         auto extension = ast::ParseExtension(name.value);
-        if (extension == ast::Extension::kNone) {
+        if (extension == ast::Extension::kInvalid) {
             return add_error(name.source, "unsupported extension: '" + name.value + "'");
         }
         builder_.AST().AddEnable(create<ast::Enable>(name.source, extension));
@@ -920,55 +887,11 @@
 //  | 'rgba32float'
 Expect<ast::TexelFormat> ParserImpl::expect_texel_format(std::string_view use) {
     auto& t = next();
-    if (t == "rgba8unorm") {
-        return ast::TexelFormat::kRgba8Unorm;
+    auto fmt = ast::ParseTexelFormat(t.to_str());
+    if (fmt == ast::TexelFormat::kInvalid) {
+        return add_error(t.source(), "invalid format", use);
     }
-    if (t == "rgba8snorm") {
-        return ast::TexelFormat::kRgba8Snorm;
-    }
-    if (t == "rgba8uint") {
-        return ast::TexelFormat::kRgba8Uint;
-    }
-    if (t == "rgba8sint") {
-        return ast::TexelFormat::kRgba8Sint;
-    }
-    if (t == "rgba16uint") {
-        return ast::TexelFormat::kRgba16Uint;
-    }
-    if (t == "rgba16sint") {
-        return ast::TexelFormat::kRgba16Sint;
-    }
-    if (t == "rgba16float") {
-        return ast::TexelFormat::kRgba16Float;
-    }
-    if (t == "r32uint") {
-        return ast::TexelFormat::kR32Uint;
-    }
-    if (t == "r32sint") {
-        return ast::TexelFormat::kR32Sint;
-    }
-    if (t == "r32float") {
-        return ast::TexelFormat::kR32Float;
-    }
-    if (t == "rg32uint") {
-        return ast::TexelFormat::kRg32Uint;
-    }
-    if (t == "rg32sint") {
-        return ast::TexelFormat::kRg32Sint;
-    }
-    if (t == "rg32float") {
-        return ast::TexelFormat::kRg32Float;
-    }
-    if (t == "rgba32uint") {
-        return ast::TexelFormat::kRgba32Uint;
-    }
-    if (t == "rgba32sint") {
-        return ast::TexelFormat::kRgba32Sint;
-    }
-    if (t == "rgba32float") {
-        return ast::TexelFormat::kRgba32Float;
-    }
-    return add_error(t.source(), "invalid format", use);
+    return fmt;
 }
 
 // variable_ident_decl
@@ -1558,14 +1481,14 @@
     return add_error(peek(), "invalid value for stage attribute");
 }
 
-Expect<ast::Builtin> ParserImpl::expect_builtin() {
+Expect<ast::BuiltinValue> ParserImpl::expect_builtin() {
     auto ident = expect_ident("builtin");
     if (ident.errored) {
         return Failure::kErrored;
     }
 
-    ast::Builtin builtin = ident_to_builtin(ident.value);
-    if (builtin == ast::Builtin::kNone) {
+    ast::BuiltinValue builtin = ast::ParseBuiltinValue(ident.value);
+    if (builtin == ast::BuiltinValue::kInvalid) {
         return add_error(ident.source, "invalid value for builtin attribute");
     }
 
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index f86d865..3e378c7 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -475,7 +475,7 @@
     /// Parses a builtin identifier, erroring if the next token does not match a
     /// valid builtin name.
     /// @returns the parsed builtin.
-    Expect<ast::Builtin> expect_builtin();
+    Expect<ast::BuiltinValue> expect_builtin();
     /// Parses a `body_stmt` grammar element, erroring on parse failure.
     /// @returns the parsed statements
     Expect<ast::BlockStatement*> expect_body_stmt();
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 99cd1f2..86a2f68 100644
--- a/src/tint/reader/wgsl/parser_impl_param_list_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_param_list_test.cc
@@ -105,7 +105,7 @@
     auto attrs_0 = e.value[0]->attributes;
     ASSERT_EQ(attrs_0.size(), 1u);
     EXPECT_TRUE(attrs_0[0]->Is<ast::BuiltinAttribute>());
-    EXPECT_EQ(attrs_0[0]->As<ast::BuiltinAttribute>()->builtin, ast::Builtin::kPosition);
+    EXPECT_EQ(attrs_0[0]->As<ast::BuiltinAttribute>()->builtin, ast::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_storage_class_test.cc b/src/tint/reader/wgsl/parser_impl_storage_class_test.cc
index d83bbf4..c40752a 100644
--- a/src/tint/reader/wgsl/parser_impl_storage_class_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_storage_class_test.cc
@@ -26,9 +26,9 @@
     return out;
 }
 
-class StorageClassTest : public ParserImplTestWithParam<StorageClassData> {};
+class ParserStorageClassTest : public ParserImplTestWithParam<StorageClassData> {};
 
-TEST_P(StorageClassTest, Parses) {
+TEST_P(ParserStorageClassTest, Parses) {
     auto params = GetParam();
     auto p = parser(params.input);
 
@@ -42,7 +42,7 @@
 }
 INSTANTIATE_TEST_SUITE_P(
     ParserImplTest,
-    StorageClassTest,
+    ParserStorageClassTest,
     testing::Values(StorageClassData{"uniform", ast::StorageClass::kUniform},
                     StorageClassData{"workgroup", ast::StorageClass::kWorkgroup},
                     StorageClassData{"storage", ast::StorageClass::kStorage},
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 133dd36..e1da7b7 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
@@ -33,7 +33,7 @@
     ASSERT_TRUE(attr_0->Is<ast::LocationAttribute>());
     EXPECT_EQ(attr_0->As<ast::LocationAttribute>()->value, 4u);
     ASSERT_TRUE(attr_1->Is<ast::BuiltinAttribute>());
-    EXPECT_EQ(attr_1->As<ast::BuiltinAttribute>()->builtin, ast::Builtin::kPosition);
+    EXPECT_EQ(attr_1->As<ast::BuiltinAttribute>()->builtin, ast::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 01e4260..f338f62 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
@@ -89,7 +89,7 @@
 
 struct BuiltinData {
     const char* input;
-    ast::Builtin result;
+    ast::BuiltinValue result;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
     out << std::string(data.input);
@@ -133,19 +133,18 @@
 INSTANTIATE_TEST_SUITE_P(
     ParserImplTest,
     BuiltinTest,
-    testing::Values(BuiltinData{"position", ast::Builtin::kPosition},
-                    BuiltinData{"vertex_index", ast::Builtin::kVertexIndex},
-                    BuiltinData{"instance_index", ast::Builtin::kInstanceIndex},
-                    BuiltinData{"front_facing", ast::Builtin::kFrontFacing},
-                    BuiltinData{"frag_depth", ast::Builtin::kFragDepth},
-                    BuiltinData{"local_invocation_id", ast::Builtin::kLocalInvocationId},
-                    BuiltinData{"local_invocation_idx", ast::Builtin::kLocalInvocationIndex},
-                    BuiltinData{"local_invocation_index", ast::Builtin::kLocalInvocationIndex},
-                    BuiltinData{"global_invocation_id", ast::Builtin::kGlobalInvocationId},
-                    BuiltinData{"workgroup_id", ast::Builtin::kWorkgroupId},
-                    BuiltinData{"num_workgroups", ast::Builtin::kNumWorkgroups},
-                    BuiltinData{"sample_index", ast::Builtin::kSampleIndex},
-                    BuiltinData{"sample_mask", ast::Builtin::kSampleMask}));
+    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}));
 
 TEST_F(ParserImplTest, Attribute_Builtin_MissingLeftParen) {
     auto p = parser("builtin position)");
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 5f69277..2cb8905 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -93,7 +93,7 @@
         case AttributeKind::kBinding:
             return {builder.create<ast::BindingAttribute>(source, 1u)};
         case AttributeKind::kBuiltin:
-            return {builder.Builtin(source, ast::Builtin::kPosition)};
+            return {builder.Builtin(source, ast::BuiltinValue::kPosition)};
         case AttributeKind::kGroup:
             return {builder.create<ast::GroupAttribute>(source, 1u)};
         case AttributeKind::kId:
@@ -250,7 +250,7 @@
     auto& params = GetParam();
     auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
     if (params.kind != AttributeKind::kBuiltin && params.kind != AttributeKind::kLocation) {
-        attrs.push_back(Builtin(Source{{34, 56}}, ast::Builtin::kPosition));
+        attrs.push_back(Builtin(Source{{34, 56}}, ast::BuiltinValue::kPosition));
     }
     auto* p = Param("a", ty.vec4<f32>(), attrs);
     Func("frag_main", {p}, ty.void_(), {},
@@ -298,7 +298,7 @@
              Stage(ast::PipelineStage::kVertex),
          },
          {
-             Builtin(ast::Builtin::kPosition),
+             Builtin(ast::BuiltinValue::kPosition),
          });
 
     if (params.should_pass) {
@@ -442,7 +442,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_back(Builtin(Source{{34, 56}}, ast::Builtin::kPosition));
+        attrs.push_back(Builtin(Source{{34, 56}}, ast::BuiltinValue::kPosition));
     }
     Func("vertex_main", {}, ty.vec4<f32>(),
          {
@@ -645,7 +645,7 @@
                               Member("a", ty.vec4<f32>(),
                                      {
                                          Invariant(),
-                                         Builtin(ast::Builtin::kPosition),
+                                         Builtin(ast::BuiltinValue::kPosition),
                                      }),
                           });
     WrapInFunction();
@@ -1140,9 +1140,9 @@
 namespace {
 using InvariantAttributeTests = ResolverTest;
 TEST_F(InvariantAttributeTests, InvariantWithPosition) {
-    auto* param =
-        Param("p", ty.vec4<f32>(),
-              {Invariant(Source{{12, 34}}), Builtin(Source{{56, 78}}, ast::Builtin::kPosition)});
+    auto* param = Param(
+        "p", ty.vec4<f32>(),
+        {Invariant(Source{{12, 34}}), Builtin(Source{{56, 78}}, ast::BuiltinValue::kPosition)});
     Func("main", {param}, ty.vec4<f32>(),
          {
              Return(Construct(ty.vec4<f32>())),
@@ -1368,10 +1368,11 @@
 }
 
 TEST_F(InterpolateTest, VertexOutput_Integer_MissingFlatInterpolation) {
-    auto* s = Structure("S", {
-                                 Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
-                                 Member(Source{{12, 34}}, "u", ty.u32(), {Location(0)}),
-                             });
+    auto* s =
+        Structure("S", {
+                           Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)}),
+                           Member(Source{{12, 34}}, "u", ty.u32(), {Location(0)}),
+                       });
     Func("main", {}, ty.Of(s),
          {
              Return(Construct(ty.Of(s))),
@@ -1392,7 +1393,7 @@
          {
              Param("a", ty.vec4<f32>(),
                    {
-                       Builtin(ast::Builtin::kPosition),
+                       Builtin(ast::BuiltinValue::kPosition),
                        Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
                                    ast::InterpolationSampling::kNone),
                    }),
@@ -1416,7 +1417,7 @@
              Stage(ast::PipelineStage::kVertex),
          },
          {
-             Builtin(ast::Builtin::kPosition),
+             Builtin(ast::BuiltinValue::kPosition),
              Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
                          ast::InterpolationSampling::kNone),
          });
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 9d8d11e..74367d1 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -1068,6 +1068,70 @@
 
     EXPECT_FALSE(r()->Resolve());
 
+    EXPECT_EQ(r()->error(),
+              "error: no matching call to " + std::string(param.name) +
+                  "(i32, i32, i32)\n\n"
+                  "2 candidate functions:\n  " +
+                  std::string(param.name) + "(T, T) -> T  where: T is abstract-float or f32\n  " +
+                  std::string(param.name) +
+                  "(vecN<T>, vecN<T>) -> vecN<T>  where: T is abstract-float or f32\n");
+}
+
+TEST_P(ResolverBuiltinTest_TwoParam, Error_NoParams) {
+    auto param = GetParam();
+
+    auto* call = Call(param.name);
+    WrapInFunction(call);
+
+    EXPECT_FALSE(r()->Resolve());
+
+    EXPECT_EQ(r()->error(),
+              "error: no matching call to " + std::string(param.name) +
+                  "()\n\n"
+                  "2 candidate functions:\n  " +
+                  std::string(param.name) + "(T, T) -> T  where: T is abstract-float or f32\n  " +
+                  std::string(param.name) +
+                  "(vecN<T>, vecN<T>) -> vecN<T>  where: T is abstract-float or f32\n");
+}
+
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverBuiltinTest_TwoParam,
+                         testing::Values(BuiltinData{"atan2", BuiltinType::kAtan2}));
+
+using ResolverBuiltinTest_TwoParam_NoConstEval = ResolverTestWithParam<BuiltinData>;
+TEST_P(ResolverBuiltinTest_TwoParam_NoConstEval, Scalar) {
+    auto param = GetParam();
+
+    auto* call = Call(param.name, 1_f, 1_f);
+    WrapInFunction(call);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+}
+
+TEST_P(ResolverBuiltinTest_TwoParam_NoConstEval, Vector) {
+    auto param = GetParam();
+
+    auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
+    WrapInFunction(call);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+}
+
+TEST_P(ResolverBuiltinTest_TwoParam_NoConstEval, Error_NoTooManyParams) {
+    auto param = GetParam();
+
+    auto* call = Call(param.name, 1_i, 2_i, 3_i);
+    WrapInFunction(call);
+
+    EXPECT_FALSE(r()->Resolve());
+
     EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
                                 "(i32, i32, i32)\n\n"
                                 "2 candidate functions:\n  " +
@@ -1075,7 +1139,7 @@
                                 std::string(param.name) + "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
 }
 
-TEST_P(ResolverBuiltinTest_TwoParam, Error_NoParams) {
+TEST_P(ResolverBuiltinTest_TwoParam_NoConstEval, Error_NoParams) {
     auto param = GetParam();
 
     auto* call = Call(param.name);
@@ -1091,9 +1155,8 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
-                         ResolverBuiltinTest_TwoParam,
-                         testing::Values(BuiltinData{"atan2", BuiltinType::kAtan2},
-                                         BuiltinData{"pow", BuiltinType::kPow},
+                         ResolverBuiltinTest_TwoParam_NoConstEval,
+                         testing::Values(BuiltinData{"pow", BuiltinType::kPow},
                                          BuiltinData{"step", BuiltinType::kStep}));
 
 TEST_F(ResolverBuiltinTest, Distance_Scalar) {
@@ -1352,14 +1415,16 @@
 
     EXPECT_FALSE(r()->Resolve());
 
-    EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
-                                "()\n\n"
-                                "2 candidate functions:\n  " +
-                                std::string(param.name) +
-                                "(T, T, T) -> T  where: T is f32, i32 or u32\n  " +
-                                std::string(param.name) +
-                                "(vecN<T>, vecN<T>, vecN<T>) -> vecN<T>  where: T is f32, i32 "
-                                "or u32\n");
+    EXPECT_EQ(
+        r()->error(),
+        "error: no matching call to " + std::string(param.name) +
+            "()\n\n"
+            "2 candidate functions:\n  " +
+            std::string(param.name) +
+            "(T, T, T) -> T  where: T is abstract-float, abstract-int, f32, i32 or u32\n  " +
+            std::string(param.name) +
+            "(vecN<T>, vecN<T>, vecN<T>) -> vecN<T>  where: T is abstract-float, abstract-int, "
+            "f32, i32 or u32\n");
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc
index 3737ae0..be7a23f 100644
--- a/src/tint/resolver/builtin_validation_test.cc
+++ b/src/tint/resolver/builtin_validation_test.cc
@@ -384,7 +384,7 @@
 TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithExtension) {
     // enable chromium_experimental_dp4a;
     // fn func { return dot4I8Packed(1u, 2u); }
-    Enable(ast::Extension::kChromiumExperimentalDP4a);
+    Enable(ast::Extension::kChromiumExperimentalDp4A);
 
     Func("func", {}, ty.i32(),
          {
@@ -412,7 +412,7 @@
 TEST_F(ResolverDP4aExtensionValidationTest, Dot4U8PackedWithExtension) {
     // enable chromium_experimental_dp4a;
     // fn func { return dot4U8Packed(1u, 2u); }
-    Enable(ast::Extension::kChromiumExperimentalDP4a);
+    Enable(ast::Extension::kChromiumExperimentalDp4A);
 
     Func("func", {}, ty.u32(),
          {
diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc
index 15fd2b6..c3ec4a7 100644
--- a/src/tint/resolver/builtins_validation_test.cc
+++ b/src/tint/resolver/builtins_validation_test.cc
@@ -33,59 +33,67 @@
 namespace StageTest {
 struct Params {
     builder::ast_type_func_ptr type;
-    ast::Builtin builtin;
+    ast::BuiltinValue builtin;
     ast::PipelineStage stage;
     bool is_valid;
 };
 
 template <typename T>
-constexpr Params ParamsFor(ast::Builtin builtin, ast::PipelineStage stage, bool is_valid) {
+constexpr Params ParamsFor(ast::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::Builtin::kPosition, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec4<f32>>(ast::Builtin::kPosition, ast::PipelineStage::kFragment, true),
-    ParamsFor<vec4<f32>>(ast::Builtin::kPosition, ast::PipelineStage::kCompute, false),
+    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<u32>(ast::Builtin::kVertexIndex, ast::PipelineStage::kVertex, true),
-    ParamsFor<u32>(ast::Builtin::kVertexIndex, ast::PipelineStage::kFragment, false),
-    ParamsFor<u32>(ast::Builtin::kVertexIndex, 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>(ast::Builtin::kInstanceIndex, ast::PipelineStage::kVertex, true),
-    ParamsFor<u32>(ast::Builtin::kInstanceIndex, ast::PipelineStage::kFragment, false),
-    ParamsFor<u32>(ast::Builtin::kInstanceIndex, 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<bool>(ast::Builtin::kFrontFacing, ast::PipelineStage::kVertex, false),
-    ParamsFor<bool>(ast::Builtin::kFrontFacing, ast::PipelineStage::kFragment, true),
-    ParamsFor<bool>(ast::Builtin::kFrontFacing, 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<vec3<u32>>(ast::Builtin::kLocalInvocationId, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec3<u32>>(ast::Builtin::kLocalInvocationId, ast::PipelineStage::kFragment, false),
-    ParamsFor<vec3<u32>>(ast::Builtin::kLocalInvocationId, ast::PipelineStage::kCompute, true),
+    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::Builtin::kLocalInvocationIndex, ast::PipelineStage::kVertex, false),
-    ParamsFor<u32>(ast::Builtin::kLocalInvocationIndex, ast::PipelineStage::kFragment, false),
-    ParamsFor<u32>(ast::Builtin::kLocalInvocationIndex, 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::Builtin::kGlobalInvocationId, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec3<u32>>(ast::Builtin::kGlobalInvocationId, ast::PipelineStage::kFragment, false),
-    ParamsFor<vec3<u32>>(ast::Builtin::kGlobalInvocationId, ast::PipelineStage::kCompute, true),
+    ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+                         ast::PipelineStage::kVertex,
+                         false),
+    ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+                         ast::PipelineStage::kFragment,
+                         false),
+    ParamsFor<vec3<u32>>(ast::BuiltinValue::kGlobalInvocationId,
+                         ast::PipelineStage::kCompute,
+                         true),
 
-    ParamsFor<vec3<u32>>(ast::Builtin::kWorkgroupId, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec3<u32>>(ast::Builtin::kWorkgroupId, ast::PipelineStage::kFragment, false),
-    ParamsFor<vec3<u32>>(ast::Builtin::kWorkgroupId, 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<vec3<u32>>(ast::Builtin::kNumWorkgroups, ast::PipelineStage::kVertex, false),
-    ParamsFor<vec3<u32>>(ast::Builtin::kNumWorkgroups, ast::PipelineStage::kFragment, false),
-    ParamsFor<vec3<u32>>(ast::Builtin::kNumWorkgroups, 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<u32>(ast::Builtin::kSampleIndex, ast::PipelineStage::kVertex, false),
-    ParamsFor<u32>(ast::Builtin::kSampleIndex, ast::PipelineStage::kFragment, true),
-    ParamsFor<u32>(ast::Builtin::kSampleIndex, ast::PipelineStage::kCompute, false),
+    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<u32>(ast::Builtin::kSampleMask, ast::PipelineStage::kVertex, false),
-    ParamsFor<u32>(ast::Builtin::kSampleMask, ast::PipelineStage::kFragment, true),
-    ParamsFor<u32>(ast::Builtin::kSampleMask, ast::PipelineStage::kCompute, false),
+    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),
 };
 
 using ResolverBuiltinsStageTest = ResolverTestWithParam<Params>;
@@ -97,7 +105,7 @@
     switch (params.stage) {
         case ast::PipelineStage::kVertex:
             Func("main", {input}, ty.vec4<f32>(), {Return(p)}, {Stage(ast::PipelineStage::kVertex)},
-                 {Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
+                 {Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition)});
             break;
         case ast::PipelineStage::kFragment:
             Func("main", {input}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)}, {});
@@ -134,7 +142,7 @@
     // ) -> @location(0) f32 { return 1.0; }
     Func("fs_main",
          {
-             Param("fd", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)}),
+             Param("fd", ty.f32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth)}),
          },
          ty.f32(),
          {
@@ -159,11 +167,11 @@
     // @fragment
     // fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
 
-    auto* s = Structure(
-        "MyInputs",
-        {
-            Member("frag_depth", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)}),
-        });
+    auto* s = Structure("MyInputs",
+                        {
+                            Member("frag_depth", ty.f32(),
+                                   {Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth)}),
+                        });
 
     Func("fragShader",
          {
@@ -193,7 +201,7 @@
     // @fragment
     // fn fragShader() { var s : S; }
 
-    Structure("S", {Member("idx", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)})});
+    Structure("S", {Member("idx", ty.u32(), {Builtin(ast::BuiltinValue::kVertexIndex)})});
 
     Func("fragShader", {}, ty.void_(), {Decl(Var("s", ty.type_name("S")))},
          {Stage(ast::PipelineStage::kFragment)});
@@ -212,7 +220,7 @@
     auto* s =
         Structure("MyInputs", {
                                   Member("position", ty.vec4<u32>(),
-                                         {Builtin(Source{{12, 34}}, ast::Builtin::kPosition)}),
+                                         {Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition)}),
                               });
     Func("fragShader",
          {
@@ -237,7 +245,7 @@
     // @vertex
     // fn main() -> @builtin(position) f32 { return 1.0; }
     Func("main", {}, ty.f32(), {Return(1_f)}, {Stage(ast::PipelineStage::kVertex)},
-         {Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
+         {Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition)});
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
@@ -250,11 +258,11 @@
     // @fragment
     // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-    auto* s = Structure(
-        "MyInputs",
-        {
-            Member("frag_depth", ty.i32(), {Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)}),
-        });
+    auto* s = Structure("MyInputs",
+                        {
+                            Member("frag_depth", ty.i32(),
+                                   {Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth)}),
+                        });
     Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(),
          {
              Return(1_f),
@@ -277,11 +285,11 @@
     // @fragment
     // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-    auto* s =
-        Structure("MyInputs",
-                  {
-                      Member("m", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)}),
-                  });
+    auto* s = Structure(
+        "MyInputs",
+        {
+            Member("m", ty.f32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask)}),
+        });
     Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
          {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
@@ -293,7 +301,7 @@
     // @fragment
     // fn main() -> @builtin(sample_mask) i32 { return 1; }
     Func("main", {}, ty.i32(), {Return(1_i)}, {Stage(ast::PipelineStage::kFragment)},
-         {Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
+         {Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask)});
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
@@ -306,7 +314,7 @@
     // ) -> @location(0) f32 { return 1.0; }
     Func("fs_main",
          {
-             Param("arg", ty.bool_(), {Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)}),
+             Param("arg", ty.bool_(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleMask)}),
          },
          ty.f32(),
          {
@@ -332,7 +340,7 @@
     auto* s = Structure(
         "MyInputs",
         {
-            Member("m", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kSampleIndex)}),
+            Member("m", ty.f32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleIndex)}),
         });
     Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
          {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
@@ -348,7 +356,7 @@
     // ) -> @location(0) f32 { return 1.0; }
     Func("fs_main",
          {
-             Param("arg", ty.bool_(), {Builtin(Source{{12, 34}}, ast::Builtin::kSampleIndex)}),
+             Param("arg", ty.bool_(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kSampleIndex)}),
          },
          ty.f32(), {Return(1_f)},
          {
@@ -368,7 +376,7 @@
     // ) -> @location(0) f32 { return 1.0; }
     Func("fs_main",
          {
-             Param("p", ty.vec3<f32>(), {Builtin(Source{{12, 34}}, ast::Builtin::kPosition)}),
+             Param("p", ty.vec3<f32>(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kPosition)}),
          },
          ty.f32(), {Return(1_f)},
          {
@@ -386,7 +394,7 @@
     // fn fs_main() -> @builtin(kFragDepth) f32 { var fd: i32; return fd; }
     auto* fd = Var("fd", ty.i32());
     Func("fs_main", {}, ty.i32(), {Decl(fd), Return(fd)}, {Stage(ast::PipelineStage::kFragment)},
-         {Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
+         {Builtin(Source{{12, 34}}, ast::BuiltinValue::kFragDepth)});
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(frag_depth) must be 'f32'");
 }
@@ -397,10 +405,10 @@
     //   @builtin(kVertexIndex) vi : f32,
     //   @builtin(kPosition) p :vec4<f32>
     // ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
-    auto* p = Param("p", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
-    auto* vi = Param("vi", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
+    auto* p = Param("p", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)});
+    auto* vi = Param("vi", ty.f32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kVertexIndex)});
     Func("main", {vi, p}, ty.vec4<f32>(), {Return(Expr("p"))}, {Stage(ast::PipelineStage::kVertex)},
-         {Builtin(ast::Builtin::kPosition)});
+         {Builtin(ast::BuiltinValue::kPosition)});
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(vertex_index) must be 'u32'");
 }
@@ -411,10 +419,11 @@
     //   @builtin(kInstanceIndex) ii : f32,
     //   @builtin(kPosition) p :vec4<f32>
     // ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
-    auto* p = Param("p", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
-    auto* ii = Param("ii", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kInstanceIndex)});
+    auto* p = Param("p", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)});
+    auto* ii =
+        Param("ii", ty.f32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kInstanceIndex)});
     Func("main", {ii, p}, ty.vec4<f32>(), {Return(Expr("p"))}, {Stage(ast::PipelineStage::kVertex)},
-         {Builtin(ast::Builtin::kPosition)});
+         {Builtin(ast::BuiltinValue::kPosition)});
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(instance_index) must be 'u32'");
 }
@@ -427,13 +436,13 @@
     //   @builtin(sample_index) si: u32,
     //   @builtin(sample_mask) sm : u32
     // ) -> @builtin(frag_depth) f32 { var fd: f32; return fd; }
-    auto* p = Param("p", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
-    auto* ff = Param("ff", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)});
-    auto* si = Param("si", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
-    auto* sm = Param("sm", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
+    auto* p = Param("p", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)});
+    auto* ff = Param("ff", ty.bool_(), {Builtin(ast::BuiltinValue::kFrontFacing)});
+    auto* si = Param("si", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)});
+    auto* sm = Param("sm", ty.u32(), {Builtin(ast::BuiltinValue::kSampleMask)});
     auto* var_fd = Var("fd", ty.f32());
     Func("fs_main", {p, ff, si, sm}, ty.f32(), {Decl(var_fd), Return(var_fd)},
-         {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
+         {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::BuiltinValue::kFragDepth)});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
@@ -443,16 +452,17 @@
     //   @builtin(vertex_index) vi : u32,
     //   @builtin(instance_index) ii : u32,
     // ) -> @builtin(position) vec4<f32> { var p :vec4<f32>; return p; }
-    auto* vi = Param("vi", ty.u32(), {Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
+    auto* vi = Param("vi", ty.u32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kVertexIndex)});
 
-    auto* ii = Param("ii", ty.u32(), {Builtin(Source{{12, 34}}, ast::Builtin::kInstanceIndex)});
+    auto* ii =
+        Param("ii", ty.u32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kInstanceIndex)});
     auto* p = Var("p", ty.vec4<f32>());
     Func("main", {vi, ii}, ty.vec4<f32>(),
          {
              Decl(p),
              Return(p),
          },
-         {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::Builtin::kPosition)});
+         {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::BuiltinValue::kPosition)});
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -467,11 +477,12 @@
     //   @builtin(num_workgroups) nwgs: vec3<u32>,
     // ) {}
 
-    auto* li_id = Param("li_id", ty.vec3<u32>(), {Builtin(ast::Builtin::kLocalInvocationId)});
-    auto* li_index = Param("li_index", ty.u32(), {Builtin(ast::Builtin::kLocalInvocationIndex)});
-    auto* gi = Param("gi", ty.vec3<u32>(), {Builtin(ast::Builtin::kGlobalInvocationId)});
-    auto* wi = Param("wi", ty.vec3<u32>(), {Builtin(ast::Builtin::kWorkgroupId)});
-    auto* nwgs = Param("nwgs", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)});
+    auto* li_id = Param("li_id", ty.vec3<u32>(), {Builtin(ast::BuiltinValue::kLocalInvocationId)});
+    auto* li_index =
+        Param("li_index", ty.u32(), {Builtin(ast::BuiltinValue::kLocalInvocationIndex)});
+    auto* gi = Param("gi", ty.vec3<u32>(), {Builtin(ast::BuiltinValue::kGlobalInvocationId)});
+    auto* wi = Param("wi", ty.vec3<u32>(), {Builtin(ast::BuiltinValue::kWorkgroupId)});
+    auto* nwgs = Param("nwgs", ty.vec3<u32>(), {Builtin(ast::BuiltinValue::kNumWorkgroups)});
 
     Func("main", {li_id, li_index, gi, wi, nwgs}, ty.void_(), {},
          {Stage(ast::PipelineStage::kCompute),
@@ -481,7 +492,7 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_WorkGroupIdNotVec3U32) {
-    auto* wi = Param("wi", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kWorkgroupId)});
+    auto* wi = Param("wi", ty.f32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kWorkgroupId)});
     Func("main", {wi}, ty.void_(), {},
          {Stage(ast::PipelineStage::kCompute),
           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
@@ -493,7 +504,8 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_NumWorkgroupsNotVec3U32) {
-    auto* nwgs = Param("nwgs", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kNumWorkgroups)});
+    auto* nwgs =
+        Param("nwgs", ty.f32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kNumWorkgroups)});
     Func("main", {nwgs}, ty.void_(), {},
          {Stage(ast::PipelineStage::kCompute),
           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
@@ -505,8 +517,8 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_GlobalInvocationNotVec3U32) {
-    auto* gi =
-        Param("gi", ty.vec3<i32>(), {Builtin(Source{{12, 34}}, ast::Builtin::kGlobalInvocationId)});
+    auto* gi = Param("gi", ty.vec3<i32>(),
+                     {Builtin(Source{{12, 34}}, ast::BuiltinValue::kGlobalInvocationId)});
     Func("main", {gi}, ty.void_(), {},
          {Stage(ast::PipelineStage::kCompute),
           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
@@ -519,7 +531,7 @@
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationIndexNotU32) {
     auto* li_index = Param("li_index", ty.vec3<u32>(),
-                           {Builtin(Source{{12, 34}}, ast::Builtin::kLocalInvocationIndex)});
+                           {Builtin(Source{{12, 34}}, ast::BuiltinValue::kLocalInvocationIndex)});
     Func("main", {li_index}, ty.void_(), {},
          {Stage(ast::PipelineStage::kCompute),
           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
@@ -532,7 +544,7 @@
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationNotVec3U32) {
     auto* li_id = Param("li_id", ty.vec2<u32>(),
-                        {Builtin(Source{{12, 34}}, ast::Builtin::kLocalInvocationId)});
+                        {Builtin(Source{{12, 34}}, ast::BuiltinValue::kLocalInvocationId)});
     Func("main", {li_id}, ty.void_(), {},
          {Stage(ast::PipelineStage::kCompute),
           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
@@ -553,11 +565,11 @@
     // @fragment
     // fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
 
-    auto* s = Structure("MyInputs",
-                        {Member("position", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
-                         Member("front_facing", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)}),
-                         Member("sample_index", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)}),
-                         Member("sample_mask", ty.u32(), {Builtin(ast::Builtin::kSampleMask)})});
+    auto* s = Structure(
+        "MyInputs", {Member("position", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)}),
+                     Member("front_facing", ty.bool_(), {Builtin(ast::BuiltinValue::kFrontFacing)}),
+                     Member("sample_index", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)}),
+                     Member("sample_mask", ty.u32(), {Builtin(ast::BuiltinValue::kSampleMask)})});
     Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1_f)},
          {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -570,7 +582,7 @@
     // ) -> @location(0) f32 { return 1.0; }
 
     auto* is_front =
-        Param("is_front", ty.i32(), {Builtin(Source{{12, 34}}, ast::Builtin::kFrontFacing)});
+        Param("is_front", ty.i32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kFrontFacing)});
     Func("fs_main", {is_front}, ty.f32(), {Return(1_f)}, {Stage(ast::PipelineStage::kFragment)},
          {Location(0)});
 
@@ -587,7 +599,7 @@
 
     auto* s = Structure(
         "MyInputs",
-        {Member("pos", ty.f32(), {Builtin(Source{{12, 34}}, ast::Builtin::kFrontFacing)})});
+        {Member("pos", ty.f32(), {Builtin(Source{{12, 34}}, ast::BuiltinValue::kFrontFacing)})});
     Func("fragShader", {Param("is_front", ty.Of(s))}, ty.f32(), {Return(1_f)},
          {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index e1c3416..c2c6313 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -46,29 +46,62 @@
 
 namespace {
 
-/// Helper that calls 'f' passing in `c`'s value
-template <typename F>
-auto Dispatch_ia_iu32(const sem::Constant* c, F&& f) {
-    return Switch(
-        c->Type(), [&](const sem::AbstractInt*) { return f(c->As<AInt>()); },
-        [&](const sem::I32*) { return f(c->As<i32>()); },
-        [&](const sem::U32*) { return f(c->As<u32>()); });
+/// Returns the first element of a parameter pack
+template <typename T>
+T First(T&& first, ...) {
+    return std::forward<T>(first);
 }
 
-/// Helper that calls 'f' passing in `c`'s value
-template <typename F>
-auto Dispatch_fia_fi32_f16(const sem::Constant* c, F&& f) {
+/// Helper that calls `f` passing in the value of all `cs`.
+/// Assumes all `cs` are of the same type.
+template <typename F, typename... CONSTANTS>
+auto Dispatch_ia_iu32(F&& f, CONSTANTS&&... cs) {
     return Switch(
-        c->Type(), [&](const sem::AbstractInt*) { return f(c->As<AInt>()); },
-        [&](const sem::AbstractFloat*) { return f(c->As<AFloat>()); },
-        [&](const sem::F32*) { return f(c->As<f32>()); },
-        [&](const sem::I32*) { return f(c->As<i32>()); },
+        First(cs...)->Type(),  //
+        [&](const sem::AbstractInt*) { return f(cs->template As<AInt>()...); },
+        [&](const sem::I32*) { return f(cs->template As<i32>()...); },
+        [&](const sem::U32*) { return f(cs->template As<u32>()...); });
+}
+
+/// Helper that calls `f` passing in the value of all `cs`.
+/// Assumes all `cs` are of the same type.
+template <typename F, typename... CONSTANTS>
+auto Dispatch_fia_fi32_f16(F&& f, CONSTANTS&&... cs) {
+    return Switch(
+        First(cs...)->Type(),  //
+        [&](const sem::AbstractInt*) { return f(cs->template As<AInt>()...); },
+        [&](const sem::AbstractFloat*) { return f(cs->template As<AFloat>()...); },
+        [&](const sem::F32*) { return f(cs->template As<f32>()...); },
+        [&](const sem::I32*) { return f(cs->template As<i32>()...); },
         [&](const sem::F16*) {
             // TODO(crbug.com/tint/1502): Support const eval for f16
             return nullptr;
         });
 }
 
+/// Helper that calls `f` passing in the value of all `cs`.
+/// Assumes all `cs` are of the same type.
+template <typename F, typename... CONSTANTS>
+auto Dispatch_fia_fiu32(F&& f, CONSTANTS&&... cs) {
+    return Switch(
+        First(cs...)->Type(),  //
+        [&](const sem::AbstractInt*) { return f(cs->template As<AInt>()...); },
+        [&](const sem::AbstractFloat*) { return f(cs->template As<AFloat>()...); },
+        [&](const sem::F32*) { return f(cs->template As<f32>()...); },
+        [&](const sem::I32*) { return f(cs->template As<i32>()...); },
+        [&](const sem::U32*) { return f(cs->template As<u32>()...); });
+}
+
+/// Helper that calls `f` passing in the value of all `cs`.
+/// Assumes all `cs` are of the same type.
+template <typename F, typename... CONSTANTS>
+auto Dispatch_fa_f32(F&& f, CONSTANTS&&... cs) {
+    return Switch(
+        First(cs...)->Type(),  //
+        [&](const sem::AbstractFloat*) { return f(cs->template As<AFloat>()...); },
+        [&](const sem::F32*) { return f(cs->template As<f32>()...); });
+}
+
 /// ZeroTypeDispatch is a helper for calling the function `f`, passing a single zero-value argument
 /// of the C++ type that corresponds to the sem::Type `type`. For example, calling
 /// `ZeroTypeDispatch()` with a type of `sem::I32*` will call the function f with a single argument
@@ -427,21 +460,21 @@
 }
 
 /// TransformElements constructs a new constant by applying the transformation function 'f' on each
-/// of the most deeply nested elements of 'c'.
-template <typename F>
-const Constant* TransformElements(ProgramBuilder& builder, const sem::Constant* c, F&& f) {
+/// of the most deeply nested elements of 'cs'.
+template <typename F, typename... CONSTANTS>
+const Constant* TransformElements(ProgramBuilder& builder, F&& f, CONSTANTS&&... cs) {
     uint32_t n = 0;
-    auto* ty = c->Type();
+    auto* ty = First(cs...)->Type();
     auto* el_ty = sem::Type::ElementOf(ty, &n);
     if (el_ty == ty) {
-        return f(c);
+        return f(cs...);
     }
     utils::Vector<const sem::Constant*, 8> els;
     els.Reserve(n);
     for (uint32_t i = 0; i < n; i++) {
-        els.Push(TransformElements(builder, c->Index(i), f));
+        els.Push(TransformElements(builder, f, cs->Index(i)...));
     }
-    return CreateComposite(builder, c->Type(), std::move(els));
+    return CreateComposite(builder, ty, std::move(els));
 }
 
 }  // namespace
@@ -658,20 +691,23 @@
 
 const sem::Constant* ConstEval::OpComplement(const sem::Type*,
                                              utils::ConstVectorRef<const sem::Expression*> args) {
-    return TransformElements(builder, args[0]->ConstantValue(), [&](const sem::Constant* c) {
-        return Dispatch_ia_iu32(c, [&](auto i) {  //
+    auto transform = [&](const sem::Constant* c) {
+        auto create = [&](auto i) {
             return CreateElement(builder, c->Type(), decltype(i)(~i.value));
-        });
-    });
+        };
+        return Dispatch_ia_iu32(create, c);
+    };
+    return TransformElements(builder, transform, args[0]->ConstantValue());
 }
 
 const sem::Constant* ConstEval::OpMinus(const sem::Type*,
                                         utils::ConstVectorRef<const sem::Expression*> args) {
-    return TransformElements(builder, args[0]->ConstantValue(), [&](const sem::Constant* c) {
-        return Dispatch_fia_fi32_f16(c, [&](auto i) {  //
-            // For signed integrals, avoid C++ UB by not negating the smallest negative number. In
-            // WGSL, this operation is well defined to return the same value, see:
-            // https://gpuweb.github.io/gpuweb/wgsl/#arithmetic-expr.
+    auto transform = [&](const sem::Constant* c) {
+        auto create = [&](auto i) {  //
+                                     // For signed integrals, avoid C++ UB by not negating the
+                                     // smallest negative number. In WGSL, this operation is well
+                                     // defined to return the same value, see:
+                                     // https://gpuweb.github.io/gpuweb/wgsl/#arithmetic-expr.
             using T = UnwrapNumber<decltype(i)>;
             if constexpr (std::is_integral_v<T>) {
                 auto v = i.value;
@@ -682,8 +718,36 @@
             } else {
                 return CreateElement(builder, c->Type(), decltype(i)(-i.value));
             }
-        });
-    });
+        };
+        return Dispatch_fia_fi32_f16(create, c);
+    };
+    return TransformElements(builder, transform, args[0]->ConstantValue());
+}
+
+const sem::Constant* ConstEval::atan2(const sem::Type*,
+                                      utils::ConstVectorRef<const sem::Expression*> args) {
+    auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
+        auto create = [&](auto i, auto j) {
+            return CreateElement(builder, c0->Type(), decltype(i)(std::atan2(i.value, j.value)));
+        };
+        return Dispatch_fa_f32(create, c0, c1);
+    };
+    return TransformElements(builder, transform, args[0]->ConstantValue(),
+                             args[1]->ConstantValue());
+}
+
+const sem::Constant* ConstEval::clamp(const sem::Type*,
+                                      utils::ConstVectorRef<const sem::Expression*> args) {
+    auto transform = [&](const sem::Constant* c0, const sem::Constant* c1,
+                         const sem::Constant* c2) {
+        auto create = [&](auto e, auto low, auto high) {
+            return CreateElement(builder, c0->Type(),
+                                 decltype(e)(std::min(std::max(e, low), high)));
+        };
+        return Dispatch_fia_fiu32(create, c0, c1, c2);
+    };
+    return TransformElements(builder, transform, args[0]->ConstantValue(), args[1]->ConstantValue(),
+                             args[2]->ConstantValue());
 }
 
 utils::Result<const sem::Constant*> ConstEval::Convert(const sem::Type* target_ty,
diff --git a/src/tint/resolver/const_eval.h b/src/tint/resolver/const_eval.h
index 9b8a3b1..4d299f4 100644
--- a/src/tint/resolver/const_eval.h
+++ b/src/tint/resolver/const_eval.h
@@ -187,6 +187,24 @@
     const sem::Constant* OpMinus(const sem::Type* ty,
                                  utils::ConstVectorRef<const sem::Expression*> args);
 
+    ////////////////////////////////////////////////////////////////////////////
+    // Builtins
+    ////////////////////////////////////////////////////////////////////////////
+
+    /// atan2 builtin
+    /// @param ty the expression type
+    /// @param args the input arguments
+    /// @return the result value, or null if the value cannot be calculated
+    const sem::Constant* atan2(const sem::Type* ty,
+                               utils::ConstVectorRef<const sem::Expression*> args);
+
+    /// clamp builtin
+    /// @param ty the expression type
+    /// @param args the input arguments
+    /// @return the result value, or null if the value cannot be calculated
+    const sem::Constant* clamp(const sem::Type* ty,
+                               utils::ConstVectorRef<const sem::Expression*> args);
+
   private:
     /// Adds the given error message to the diagnostics
     void AddError(const std::string& msg, const Source& source) const;
diff --git a/src/tint/resolver/const_eval_test.cc b/src/tint/resolver/const_eval_test.cc
index 7991f6f..cd1855b 100644
--- a/src/tint/resolver/const_eval_test.cc
+++ b/src/tint/resolver/const_eval_test.cc
@@ -17,16 +17,73 @@
 
 #include "gtest/gtest.h"
 #include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/sem/builtin_type.h"
 #include "src/tint/sem/expression.h"
 #include "src/tint/sem/index_accessor_expression.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/test_helper.h"
+#include "src/tint/utils/transform.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::resolver {
 namespace {
 
+template <typename T>
+const auto kHighest = T(T::kHighest);
+
+template <typename T>
+const auto kLowest = T(T::kLowest);
+
+template <typename T>
+const auto kNaN = T(std::numeric_limits<UnwrapNumber<T>>::quiet_NaN());
+
+template <typename T>
+const auto kInf = T(std::numeric_limits<UnwrapNumber<T>>::infinity());
+
+template <typename T>
+const auto kPi = T(UnwrapNumber<T>(3.14159265358979323846));
+
+template <typename T>
+const auto kPiOver2 = T(UnwrapNumber<T>(1.57079632679489661923));
+
+template <typename T>
+const auto kPiOver4 = T(UnwrapNumber<T>(0.785398163397448309616));
+
+template <typename T>
+const auto k3PiOver4 = T(UnwrapNumber<T>(2.356194490192344928846));
+
+template <typename T>
+constexpr auto Negate(const Number<T>& v) {
+    // For signed integrals, avoid C++ UB by not negating the smallest negative number. In
+    // WGSL, this operation is well defined to return the same value, see:
+    // https://gpuweb.github.io/gpuweb/wgsl/#arithmetic-expr.
+    if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
+        if (v == std::numeric_limits<T>::min()) {
+            return v;
+        }
+    }
+    return -v;
+}
+
+template <typename T>
+auto Abs(const Number<T>& v) {
+    if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>) {
+        return v;
+    } else {
+        return Number<T>(std::abs(v));
+    }
+}
+
+// Concats any number of std::vectors
+template <typename Vec, typename... Vecs>
+auto Concat(Vec&& v1, Vecs&&... vs) {
+    auto total_size = v1.size() + (vs.size() + ...);
+    v1.reserve(total_size);
+    (std::move(vs.begin(), vs.end(), std::back_inserter(v1)), ...);
+    return std::move(v1);
+}
+
 using ResolverConstEvalTest = ResolverTest;
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1333,7 +1390,7 @@
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-    constexpr auto kInf = std::numeric_limits<double>::infinity();
+    constexpr auto kInfinity = std::numeric_limits<double>::infinity();
 
     auto* sem = Sem().Get(expr);
     ASSERT_NE(sem, nullptr);
@@ -1349,17 +1406,17 @@
     EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
     EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
     EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
-    EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), kInf);
+    EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), kInfinity);
 
     EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
     EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
     EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
-    EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), -kInf);
+    EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), -kInfinity);
 
     EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
     EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
     EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
-    EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), kInf);
+    EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), kInfinity);
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_Small_f32_to_f16) {
@@ -2931,29 +2988,6 @@
 namespace unary_op {
 
 template <typename T>
-auto Highest() {
-    return T(T::kHighest);
-}
-
-template <typename T>
-auto Lowest() {
-    return T(T::kLowest);
-}
-
-template <typename T>
-constexpr auto Negate(const Number<T>& v) {
-    // For signed integrals, avoid C++ UB by not negating the smallest negative number. In
-    // WGSL, this operation is well defined to return the same value, see:
-    // https://gpuweb.github.io/gpuweb/wgsl/#arithmetic-expr.
-    if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
-        if (v == std::numeric_limits<T>::min()) {
-            return v;
-        }
-    }
-    return -v;
-}
-
-template <typename T>
 struct Values {
     T input;
     T expect;
@@ -3036,37 +3070,37 @@
                                               C(-0_a, 0_a),
                                               C(1_a, -1_a),
                                               C(-1_a, 1_a),
-                                              C(Highest<AInt>(), -Highest<AInt>()),
-                                              C(-Highest<AInt>(), Highest<AInt>()),
-                                              C(Lowest<AInt>(), Negate(Lowest<AInt>())),
-                                              C(Negate(Lowest<AInt>()), Lowest<AInt>()),
+                                              C(kHighest<AInt>, -kHighest<AInt>),
+                                              C(-kHighest<AInt>, kHighest<AInt>),
+                                              C(kLowest<AInt>, Negate(kLowest<AInt>)),
+                                              C(Negate(kLowest<AInt>), kLowest<AInt>),
                                               // i32
                                               C(0_i, -0_i),
                                               C(-0_i, 0_i),
                                               C(1_i, -1_i),
                                               C(-1_i, 1_i),
-                                              C(Highest<i32>(), -Highest<i32>()),
-                                              C(-Highest<i32>(), Highest<i32>()),
-                                              C(Lowest<i32>(), Negate(Lowest<i32>())),
-                                              C(Negate(Lowest<i32>()), Lowest<i32>()),
+                                              C(kHighest<i32>, -kHighest<i32>),
+                                              C(-kHighest<i32>, kHighest<i32>),
+                                              C(kLowest<i32>, Negate(kLowest<i32>)),
+                                              C(Negate(kLowest<i32>), kLowest<i32>),
                                               // AFloat
                                               C(0.0_a, -0.0_a),
                                               C(-0.0_a, 0.0_a),
                                               C(1.0_a, -1.0_a),
                                               C(-1.0_a, 1.0_a),
-                                              C(Highest<AFloat>(), -Highest<AFloat>()),
-                                              C(-Highest<AFloat>(), Highest<AFloat>()),
-                                              C(Lowest<AFloat>(), Negate(Lowest<AFloat>())),
-                                              C(Negate(Lowest<AFloat>()), Lowest<AFloat>()),
+                                              C(kHighest<AFloat>, -kHighest<AFloat>),
+                                              C(-kHighest<AFloat>, kHighest<AFloat>),
+                                              C(kLowest<AFloat>, Negate(kLowest<AFloat>)),
+                                              C(Negate(kLowest<AFloat>), kLowest<AFloat>),
                                               // f32
                                               C(0.0_f, -0.0_f),
                                               C(-0.0_f, 0.0_f),
                                               C(1.0_f, -1.0_f),
                                               C(-1.0_f, 1.0_f),
-                                              C(Highest<f32>(), -Highest<f32>()),
-                                              C(-Highest<f32>(), Highest<f32>()),
-                                              C(Lowest<f32>(), Negate(Lowest<f32>())),
-                                              C(Negate(Lowest<f32>()), Lowest<f32>()),
+                                              C(kHighest<f32>, -kHighest<f32>),
+                                              C(-kHighest<f32>, kHighest<f32>),
+                                              C(kLowest<f32>, Negate(kLowest<f32>)),
+                                              C(Negate(kLowest<f32>), kLowest<f32>),
                                           })));
 
 // Make sure UBSan doesn't trip on C++'s undefined behaviour of negating the smallest negative
@@ -3082,5 +3116,170 @@
 
 }  // namespace unary_op
 
+namespace builtin {
+
+template <typename T>
+struct Values {
+    std::vector<T> args;
+    T result;
+    bool result_pos_or_neg;
+};
+
+struct Case {
+    std::variant<Values<AInt>, Values<AFloat>, Values<u32>, Values<i32>, Values<f32>, Values<f16>>
+        values;
+};
+
+static std::ostream& operator<<(std::ostream& o, const Case& c) {
+    std::visit(
+        [&](auto&& v) {
+            for (auto& e : v.args) {
+                o << e << ((&e != &v.args.back()) ? " " : "");
+            }
+        },
+        c.values);
+    return o;
+}
+
+template <typename T>
+Case C(std::vector<T> args, T result, bool result_pos_or_neg = false) {
+    return Case{Values<T>{std::move(args), result, result_pos_or_neg}};
+}
+
+using ResolverConstEvalBuiltinTest = ResolverTestWithParam<std::tuple<sem::BuiltinType, Case>>;
+
+TEST_P(ResolverConstEvalBuiltinTest, Test) {
+    Enable(ast::Extension::kF16);
+
+    auto builtin = std::get<0>(GetParam());
+    auto c = std::get<1>(GetParam());
+    std::visit(
+        [&](auto&& values) {
+            using T = decltype(values.result);
+            auto args = utils::Transform(values.args, [&](auto&& a) {
+                return static_cast<const ast::Expression*>(Expr(a));
+            });
+            auto* expr = Call(sem::str(builtin), std::move(args));
+
+            GlobalConst("C", nullptr, expr);
+
+            EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+            auto* sem = Sem().Get(expr);
+            const sem::Constant* value = sem->ConstantValue();
+            ASSERT_NE(value, nullptr);
+            EXPECT_TYPE(value->Type(), sem->Type());
+
+            auto actual = value->As<T>();
+
+            if constexpr (IsFloatingPoint<UnwrapNumber<T>>) {
+                if (std::isnan(values.result)) {
+                    EXPECT_TRUE(std::isnan(actual));
+                } else {
+                    EXPECT_FLOAT_EQ(values.result_pos_or_neg ? Abs(actual) : actual, values.result);
+                }
+            } else {
+                EXPECT_EQ(values.result_pos_or_neg ? Abs(actual) : actual, values.result);
+            }
+
+            if constexpr (IsInteger<UnwrapNumber<T>>) {
+                // Check that the constant's integer doesn't contain unexpected data in the MSBs
+                // that are outside of the bit-width of T.
+                EXPECT_EQ(value->As<AInt>(), AInt(values.result));
+            }
+        },
+        c.values);
+}
+
+template <typename T, bool finite_only>
+std::vector<Case> Atan2Cases() {
+    std::vector<Case> cases = {
+        // If y is +/-0 and x is negative or -0, +/-PI is returned
+        C({T(0.0), -T(0.0)}, kPi<T>, true),
+
+        // If y is +/-0 and x is positive or +0, +/-0 is returned
+        C({T(0.0), T(0.0)}, T(0.0), true),
+
+        // If x is +/-0 and y is negative, -PI/2 is returned
+        C({-T(1.0), T(0.0)}, -kPiOver2<T>),
+        C({-T(1.0), -T(0.0)}, -kPiOver2<T>),
+
+        // If x is +/-0 and y is positive, +PI/2 is returned
+        C({T(1.0), T(0.0)}, kPiOver2<T>),
+        C({T(1.0), -T(0.0)}, kPiOver2<T>),
+    };
+
+    if constexpr (!finite_only) {
+        std::vector<Case> non_finite_cases = {
+            // If y is +/-INF and x is finite, +/-PI/2 is returned
+            C({kInf<T>, T(0.0)}, kPiOver2<T>, true),
+            C({-kInf<T>, T(0.0)}, kPiOver2<T>, true),
+
+            // If y is +/-INF and x is -INF, +/-3PI/4 is returned
+            C({kInf<T>, -kInf<T>}, k3PiOver4<T>, true),
+            C({-kInf<T>, -kInf<T>}, k3PiOver4<T>, true),
+
+            // If y is +/-INF and x is +INF, +/-PI/4 is returned
+            C({kInf<T>, kInf<T>}, kPiOver4<T>, true),
+            C({-kInf<T>, kInf<T>}, kPiOver4<T>, true),
+
+            // If x is -INF and y is finite and positive, +PI is returned
+            C({T(0.0), -kInf<T>}, kPi<T>),
+
+            // If x is -INF and y is finite and negative, -PI is returned
+            C({-T(0.0), -kInf<T>}, -kPi<T>),
+
+            // If x is +INF and y is finite and positive, +0 is returned
+            C({T(0.0), kInf<T>}, T(0.0)),
+
+            // If x is +INF and y is finite and negative, -0 is returned
+            C({-T(0.0), kInf<T>}, -T(0.0)),
+
+            // If either x is NaN or y is NaN, NaN is returned
+            C({kNaN<T>, T(0.0)}, kNaN<T>),
+            C({T(0.0), kNaN<T>}, kNaN<T>),
+            C({kNaN<T>, kNaN<T>}, kNaN<T>),
+        };
+
+        cases = Concat(cases, non_finite_cases);
+    }
+
+    return cases;
+}
+
+INSTANTIATE_TEST_SUITE_P(  //
+    Atan2,
+    ResolverConstEvalBuiltinTest,
+    testing::Combine(testing::Values(sem::BuiltinType::kAtan2),
+                     testing::ValuesIn(Concat(Atan2Cases<AFloat, true>(),  //
+                                              Atan2Cases<f32, false>()))));
+
+template <typename T>
+std::vector<Case> ClampCases() {
+    return {
+        C({T(0), T(0), T(0)}, T(0)),
+        C({T(0), T(42), kHighest<T>}, T(42)),
+        C({kLowest<T>, T(0), T(42)}, T(0)),
+        C({T(0), kLowest<T>, kHighest<T>}, T(0)),
+        C({T(0), kHighest<T>, kLowest<T>}, kLowest<T>),
+        C({kHighest<T>, kHighest<T>, kHighest<T>}, kHighest<T>),
+        C({kLowest<T>, kLowest<T>, kLowest<T>}, kLowest<T>),
+        C({kHighest<T>, kLowest<T>, kHighest<T>}, kHighest<T>),
+        C({kLowest<T>, kLowest<T>, kHighest<T>}, kLowest<T>),
+    };
+}
+
+INSTANTIATE_TEST_SUITE_P(  //
+    Clamp,
+    ResolverConstEvalBuiltinTest,
+    testing::Combine(testing::Values(sem::BuiltinType::kClamp),
+                     testing::ValuesIn(Concat(ClampCases<AInt>(),  //
+                                              ClampCases<i32>(),
+                                              ClampCases<u32>(),
+                                              ClampCases<AFloat>(),
+                                              ClampCases<f32>()))));
+
+}  // namespace builtin
+
 }  // namespace
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl b/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
index 1f3d7cd..00ac21b 100644
--- a/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
+++ b/src/tint/resolver/ctor_conv_intrinsic.cc.tmpl
@@ -2,6 +2,9 @@
 --------------------------------------------------------------------------------
 Template file for use with tools/src/cmd/gen to generate ctor_conv_intrinsic.cc
 
+To update the generated file, run:
+    ./tools/run gen
+
 See:
 * tools/src/cmd/gen for structures used by this template
 * https://golang.org/pkg/text/template/ for documentation on the template syntax
diff --git a/src/tint/resolver/ctor_conv_intrinsic.h.tmpl b/src/tint/resolver/ctor_conv_intrinsic.h.tmpl
index a28eba4..349f939 100644
--- a/src/tint/resolver/ctor_conv_intrinsic.h.tmpl
+++ b/src/tint/resolver/ctor_conv_intrinsic.h.tmpl
@@ -2,6 +2,9 @@
 --------------------------------------------------------------------------------
 Template file for use with tools/src/cmd/gen to generate ctor_conv_intrinsic.h
 
+To update the generated file, run:
+    ./tools/run gen
+
 See:
 * tools/src/cmd/gen for structures used by this template
 * https://golang.org/pkg/text/template/ for documentation on the template syntax
diff --git a/src/tint/resolver/entry_point_validation_test.cc b/src/tint/resolver/entry_point_validation_test.cc
index b0495c2..8df0425 100644
--- a/src/tint/resolver/entry_point_validation_test.cc
+++ b/src/tint/resolver/entry_point_validation_test.cc
@@ -59,7 +59,7 @@
     // @vertex
     // fn main() -> @builtin(position) vec4<f32> { return vec4<f32>(); }
     Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
-         {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::Builtin::kPosition)});
+         {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::BuiltinValue::kPosition)});
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -83,7 +83,7 @@
     // }
     Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
          {Stage(ast::PipelineStage::kVertex)},
-         {Location(Source{{13, 43}}, 0), Builtin(Source{{14, 52}}, ast::Builtin::kPosition)});
+         {Location(Source{{13, 43}}, 0), Builtin(Source{{14, 52}}, ast::BuiltinValue::kPosition)});
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
@@ -101,7 +101,7 @@
     // }
     auto* output =
         Structure("Output", {Member("a", ty.f32(), {Location(0)}),
-                             Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
+                             Member("b", ty.f32(), {Builtin(ast::BuiltinValue::kFragDepth)})});
     Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
          {Stage(ast::PipelineStage::kFragment)});
 
@@ -119,7 +119,7 @@
     auto* output =
         Structure("Output", {Member("a", ty.f32(),
                                     {Location(Source{{13, 43}}, 0),
-                                     Builtin(Source{{14, 52}}, ast::Builtin::kFragDepth)})});
+                                     Builtin(Source{{14, 52}}, ast::BuiltinValue::kFragDepth)})});
     Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
          {Stage(ast::PipelineStage::kFragment)});
 
@@ -159,8 +159,8 @@
     //   return Output();
     // }
     auto* output =
-        Structure("Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}),
-                             Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
+        Structure("Output", {Member("a", ty.f32(), {Builtin(ast::BuiltinValue::kFragDepth)}),
+                             Member("b", ty.f32(), {Builtin(ast::BuiltinValue::kFragDepth)})});
     Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
          {Stage(ast::PipelineStage::kFragment)});
 
@@ -193,9 +193,9 @@
 TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Multiple) {
     // @fragment
     // fn main(@location(0) @builtin(sample_index) param : u32) {}
-    auto* param = Param(
-        "param", ty.u32(),
-        {Location(Source{{13, 43}}, 0), Builtin(Source{{14, 52}}, ast::Builtin::kSampleIndex)});
+    auto* param = Param("param", ty.u32(),
+                        {Location(Source{{13, 43}}, 0),
+                         Builtin(Source{{14, 52}}, ast::BuiltinValue::kSampleIndex)});
     Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
     EXPECT_FALSE(r()->Resolve());
@@ -212,7 +212,7 @@
     // fn main(param : Input) {}
     auto* input =
         Structure("Input", {Member("a", ty.f32(), {Location(0)}),
-                            Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
+                            Member("b", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)})});
     auto* param = Param("param", ty.Of(input));
     Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
@@ -228,7 +228,7 @@
     auto* input =
         Structure("Input", {Member("a", ty.u32(),
                                    {Location(Source{{13, 43}}, 0),
-                                    Builtin(Source{{14, 52}}, ast::Builtin::kSampleIndex)})});
+                                    Builtin(Source{{14, 52}}, ast::BuiltinValue::kSampleIndex)})});
     auto* param = Param("param", ty.Of(input));
     Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
@@ -259,8 +259,8 @@
     // @fragment
     // fn main(@builtin(sample_index) param_a : u32,
     //         @builtin(sample_index) param_b : u32) {}
-    auto* param_a = Param("param_a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
-    auto* param_b = Param("param_b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
+    auto* param_a = Param("param_a", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)});
+    auto* param_b = Param("param_b", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)});
     Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
          {Stage(ast::PipelineStage::kFragment)});
 
@@ -280,9 +280,9 @@
     // @fragment
     // fn main(param_a : InputA, param_b : InputB) {}
     auto* input_a =
-        Structure("InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
+        Structure("InputA", {Member("a", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)})});
     auto* input_b =
-        Structure("InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
+        Structure("InputB", {Member("a", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)})});
     auto* param_a = Param("param_a", ty.Of(input_a));
     auto* param_b = Param("param_b", ty.Of(input_b));
     Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
@@ -601,7 +601,7 @@
     // }
     auto* output =
         Structure("Output", {Member("a", ty.f32(), {Location(0)}),
-                             Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
+                             Member("b", ty.f32(), {Builtin(ast::BuiltinValue::kFragDepth)})});
     Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
          {Stage(ast::PipelineStage::kFragment)});
 
diff --git a/src/tint/resolver/intrinsic_table.inl b/src/tint/resolver/intrinsic_table.inl
index 632b4a7..76fa443 100644
--- a/src/tint/resolver/intrinsic_table.inl
+++ b/src/tint/resolver/intrinsic_table.inl
@@ -23,7 +23,6 @@
 // clang-format off
 
 /// TypeMatcher for 'type bool'
-/// @see src/tint/intrinsics.def:73:6
 class Bool : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -50,7 +49,6 @@
 }
 
 /// TypeMatcher for 'type fa'
-/// @see src/tint/intrinsics.def:74:48
 class Fa : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -79,7 +77,6 @@
 }
 
 /// TypeMatcher for 'type ia'
-/// @see src/tint/intrinsics.def:75:48
 class Ia : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -108,7 +105,6 @@
 }
 
 /// TypeMatcher for 'type i32'
-/// @see src/tint/intrinsics.def:76:21
 class I32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -135,7 +131,6 @@
 }
 
 /// TypeMatcher for 'type u32'
-/// @see src/tint/intrinsics.def:77:21
 class U32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -162,7 +157,6 @@
 }
 
 /// TypeMatcher for 'type f32'
-/// @see src/tint/intrinsics.def:78:21
 class F32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -189,7 +183,6 @@
 }
 
 /// TypeMatcher for 'type f16'
-/// @see src/tint/intrinsics.def:79:21
 class F16 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -216,7 +209,6 @@
 }
 
 /// TypeMatcher for 'type vec2'
-/// @see src/tint/intrinsics.def:80:6
 class Vec2 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -249,7 +241,6 @@
 }
 
 /// TypeMatcher for 'type vec3'
-/// @see src/tint/intrinsics.def:81:6
 class Vec3 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -282,7 +273,6 @@
 }
 
 /// TypeMatcher for 'type vec4'
-/// @see src/tint/intrinsics.def:82:6
 class Vec4 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -315,7 +305,6 @@
 }
 
 /// TypeMatcher for 'type mat2x2'
-/// @see src/tint/intrinsics.def:83:6
 class Mat2X2 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -348,7 +337,6 @@
 }
 
 /// TypeMatcher for 'type mat2x3'
-/// @see src/tint/intrinsics.def:84:6
 class Mat2X3 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -381,7 +369,6 @@
 }
 
 /// TypeMatcher for 'type mat2x4'
-/// @see src/tint/intrinsics.def:85:6
 class Mat2X4 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -414,7 +401,6 @@
 }
 
 /// TypeMatcher for 'type mat3x2'
-/// @see src/tint/intrinsics.def:86:6
 class Mat3X2 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -447,7 +433,6 @@
 }
 
 /// TypeMatcher for 'type mat3x3'
-/// @see src/tint/intrinsics.def:87:6
 class Mat3X3 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -480,7 +465,6 @@
 }
 
 /// TypeMatcher for 'type mat3x4'
-/// @see src/tint/intrinsics.def:88:6
 class Mat3X4 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -513,7 +497,6 @@
 }
 
 /// TypeMatcher for 'type mat4x2'
-/// @see src/tint/intrinsics.def:89:6
 class Mat4X2 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -546,7 +529,6 @@
 }
 
 /// TypeMatcher for 'type mat4x3'
-/// @see src/tint/intrinsics.def:90:6
 class Mat4X3 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -579,7 +561,6 @@
 }
 
 /// TypeMatcher for 'type mat4x4'
-/// @see src/tint/intrinsics.def:91:6
 class Mat4X4 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -612,7 +593,6 @@
 }
 
 /// TypeMatcher for 'type vec'
-/// @see src/tint/intrinsics.def:92:34
 class Vec : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -653,7 +633,6 @@
 }
 
 /// TypeMatcher for 'type mat'
-/// @see src/tint/intrinsics.def:93:34
 class Mat : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -700,7 +679,6 @@
 }
 
 /// TypeMatcher for 'type ptr'
-/// @see src/tint/intrinsics.def:94:6
 class Ptr : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -745,7 +723,6 @@
 }
 
 /// TypeMatcher for 'type atomic'
-/// @see src/tint/intrinsics.def:95:6
 class Atomic : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -778,7 +755,6 @@
 }
 
 /// TypeMatcher for 'type array'
-/// @see src/tint/intrinsics.def:96:6
 class Array : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -811,7 +787,6 @@
 }
 
 /// TypeMatcher for 'type sampler'
-/// @see src/tint/intrinsics.def:97:6
 class Sampler : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -838,7 +813,6 @@
 }
 
 /// TypeMatcher for 'type sampler_comparison'
-/// @see src/tint/intrinsics.def:98:6
 class SamplerComparison : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -865,7 +839,6 @@
 }
 
 /// TypeMatcher for 'type texture_1d'
-/// @see src/tint/intrinsics.def:99:6
 class Texture1D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -898,7 +871,6 @@
 }
 
 /// TypeMatcher for 'type texture_2d'
-/// @see src/tint/intrinsics.def:100:6
 class Texture2D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -931,7 +903,6 @@
 }
 
 /// TypeMatcher for 'type texture_2d_array'
-/// @see src/tint/intrinsics.def:101:6
 class Texture2DArray : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -964,7 +935,6 @@
 }
 
 /// TypeMatcher for 'type texture_3d'
-/// @see src/tint/intrinsics.def:102:6
 class Texture3D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -997,7 +967,6 @@
 }
 
 /// TypeMatcher for 'type texture_cube'
-/// @see src/tint/intrinsics.def:103:6
 class TextureCube : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1030,7 +999,6 @@
 }
 
 /// TypeMatcher for 'type texture_cube_array'
-/// @see src/tint/intrinsics.def:104:6
 class TextureCubeArray : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1063,7 +1031,6 @@
 }
 
 /// TypeMatcher for 'type texture_multisampled_2d'
-/// @see src/tint/intrinsics.def:105:6
 class TextureMultisampled2D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1096,7 +1063,6 @@
 }
 
 /// TypeMatcher for 'type texture_depth_2d'
-/// @see src/tint/intrinsics.def:106:6
 class TextureDepth2D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1123,7 +1089,6 @@
 }
 
 /// TypeMatcher for 'type texture_depth_2d_array'
-/// @see src/tint/intrinsics.def:107:6
 class TextureDepth2DArray : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1150,7 +1115,6 @@
 }
 
 /// TypeMatcher for 'type texture_depth_cube'
-/// @see src/tint/intrinsics.def:108:6
 class TextureDepthCube : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1177,7 +1141,6 @@
 }
 
 /// TypeMatcher for 'type texture_depth_cube_array'
-/// @see src/tint/intrinsics.def:109:6
 class TextureDepthCubeArray : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1204,7 +1167,6 @@
 }
 
 /// TypeMatcher for 'type texture_depth_multisampled_2d'
-/// @see src/tint/intrinsics.def:110:6
 class TextureDepthMultisampled2D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1231,7 +1193,6 @@
 }
 
 /// TypeMatcher for 'type texture_storage_1d'
-/// @see src/tint/intrinsics.def:111:6
 class TextureStorage1D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1270,7 +1231,6 @@
 }
 
 /// TypeMatcher for 'type texture_storage_2d'
-/// @see src/tint/intrinsics.def:112:6
 class TextureStorage2D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1309,7 +1269,6 @@
 }
 
 /// TypeMatcher for 'type texture_storage_2d_array'
-/// @see src/tint/intrinsics.def:113:6
 class TextureStorage2DArray : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1348,7 +1307,6 @@
 }
 
 /// TypeMatcher for 'type texture_storage_3d'
-/// @see src/tint/intrinsics.def:114:6
 class TextureStorage3D : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1387,7 +1345,6 @@
 }
 
 /// TypeMatcher for 'type texture_external'
-/// @see src/tint/intrinsics.def:115:6
 class TextureExternal : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1414,7 +1371,6 @@
 }
 
 /// TypeMatcher for 'type __modf_result'
-/// @see src/tint/intrinsics.def:117:6
 class ModfResult : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1441,7 +1397,6 @@
 }
 
 /// TypeMatcher for 'type __modf_result_vec'
-/// @see src/tint/intrinsics.def:118:39
 class ModfResultVec : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1476,7 +1431,6 @@
 }
 
 /// TypeMatcher for 'type __frexp_result'
-/// @see src/tint/intrinsics.def:119:6
 class FrexpResult : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1503,7 +1457,6 @@
 }
 
 /// TypeMatcher for 'type __frexp_result_vec'
-/// @see src/tint/intrinsics.def:120:40
 class FrexpResultVec : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1538,7 +1491,6 @@
 }
 
 /// TypeMatcher for 'type __atomic_compare_exchange_result'
-/// @see src/tint/intrinsics.def:122:6
 class AtomicCompareExchangeResult : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules.
@@ -1571,7 +1523,6 @@
 }
 
 /// TypeMatcher for 'match abstract_or_scalar'
-/// @see src/tint/intrinsics.def:130:7
 class AbstractOrScalar : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1621,7 +1572,6 @@
 }
 
 /// TypeMatcher for 'match scalar'
-/// @see src/tint/intrinsics.def:131:7
 class Scalar : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1665,7 +1615,6 @@
 }
 
 /// TypeMatcher for 'match scalar_no_f32'
-/// @see src/tint/intrinsics.def:132:7
 class ScalarNoF32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1706,7 +1655,6 @@
 }
 
 /// TypeMatcher for 'match scalar_no_f16'
-/// @see src/tint/intrinsics.def:133:7
 class ScalarNoF16 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1747,7 +1695,6 @@
 }
 
 /// TypeMatcher for 'match scalar_no_i32'
-/// @see src/tint/intrinsics.def:134:7
 class ScalarNoI32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1788,7 +1735,6 @@
 }
 
 /// TypeMatcher for 'match scalar_no_u32'
-/// @see src/tint/intrinsics.def:135:7
 class ScalarNoU32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1829,7 +1775,6 @@
 }
 
 /// TypeMatcher for 'match scalar_no_bool'
-/// @see src/tint/intrinsics.def:136:7
 class ScalarNoBool : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1870,7 +1815,6 @@
 }
 
 /// TypeMatcher for 'match fia_fi32_f16'
-/// @see src/tint/intrinsics.def:137:7
 class FiaFi32F16 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1913,8 +1857,84 @@
   return ss.str();
 }
 
+/// TypeMatcher for 'match fia_fiu32'
+class FiaFiu32 : public TypeMatcher {
+ public:
+  /// Checks whether the given type matches the matcher rules, and returns the
+  /// expected, canonicalized type on success.
+  /// Match may define and refine the template types and numbers in state.
+  /// @param state the MatchState
+  /// @param type the type to match
+  /// @returns the canonicalized type on match, otherwise nullptr
+  const sem::Type* Match(MatchState& state,
+                         const sem::Type* type) const override;
+  /// @param state the MatchState
+  /// @return a string representation of the matcher.
+  std::string String(MatchState* state) const override;
+};
+
+const sem::Type* FiaFiu32::Match(MatchState& state, const sem::Type* ty) const {
+  if (match_fa(ty)) {
+    return build_fa(state);
+  }
+  if (match_ia(ty)) {
+    return build_ia(state);
+  }
+  if (match_i32(ty)) {
+    return build_i32(state);
+  }
+  if (match_u32(ty)) {
+    return build_u32(state);
+  }
+  if (match_f32(ty)) {
+    return build_f32(state);
+  }
+  return nullptr;
+}
+
+std::string FiaFiu32::String(MatchState*) const {
+  std::stringstream ss;
+  // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+  // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+  ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
+  return ss.str();
+}
+
+/// TypeMatcher for 'match fa_f32'
+class FaF32 : public TypeMatcher {
+ public:
+  /// Checks whether the given type matches the matcher rules, and returns the
+  /// expected, canonicalized type on success.
+  /// Match may define and refine the template types and numbers in state.
+  /// @param state the MatchState
+  /// @param type the type to match
+  /// @returns the canonicalized type on match, otherwise nullptr
+  const sem::Type* Match(MatchState& state,
+                         const sem::Type* type) const override;
+  /// @param state the MatchState
+  /// @return a string representation of the matcher.
+  std::string String(MatchState* state) const override;
+};
+
+const sem::Type* FaF32::Match(MatchState& state, const sem::Type* ty) const {
+  if (match_fa(ty)) {
+    return build_fa(state);
+  }
+  if (match_f32(ty)) {
+    return build_f32(state);
+  }
+  return nullptr;
+}
+
+std::string FaF32::String(MatchState*) const {
+  std::stringstream ss;
+  // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+  // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+  ss << Fa().String(nullptr) << " or " << F32().String(nullptr);
+  return ss.str();
+}
+
 /// TypeMatcher for 'match fa_f32_f16'
-/// @see src/tint/intrinsics.def:138:7
 class FaF32F16 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1952,7 +1972,6 @@
 }
 
 /// TypeMatcher for 'match ia_iu32'
-/// @see src/tint/intrinsics.def:139:7
 class IaIu32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -1990,7 +2009,6 @@
 }
 
 /// TypeMatcher for 'match fiu32_f16'
-/// @see src/tint/intrinsics.def:140:7
 class Fiu32F16 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -2031,7 +2049,6 @@
 }
 
 /// TypeMatcher for 'match fiu32'
-/// @see src/tint/intrinsics.def:141:7
 class Fiu32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -2069,7 +2086,6 @@
 }
 
 /// TypeMatcher for 'match fi32_f16'
-/// @see src/tint/intrinsics.def:142:7
 class Fi32F16 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -2107,7 +2123,6 @@
 }
 
 /// TypeMatcher for 'match fi32'
-/// @see src/tint/intrinsics.def:143:7
 class Fi32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -2142,7 +2157,6 @@
 }
 
 /// TypeMatcher for 'match f32_f16'
-/// @see src/tint/intrinsics.def:144:7
 class F32F16 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -2177,7 +2191,6 @@
 }
 
 /// TypeMatcher for 'match iu32'
-/// @see src/tint/intrinsics.def:145:7
 class Iu32 : public TypeMatcher {
  public:
   /// Checks whether the given type matches the matcher rules, and returns the
@@ -2212,7 +2225,6 @@
 }
 
 /// EnumMatcher for 'match f32_texel_format'
-/// @see src/tint/intrinsics.def:156:7
 class F32TexelFormat : public NumberMatcher {
  public:
   /// Checks whether the given number matches the enum matcher rules.
@@ -2245,7 +2257,6 @@
 }
 
 /// EnumMatcher for 'match i32_texel_format'
-/// @see src/tint/intrinsics.def:163:7
 class I32TexelFormat : public NumberMatcher {
  public:
   /// Checks whether the given number matches the enum matcher rules.
@@ -2277,7 +2288,6 @@
 }
 
 /// EnumMatcher for 'match u32_texel_format'
-/// @see src/tint/intrinsics.def:169:7
 class U32TexelFormat : public NumberMatcher {
  public:
   /// Checks whether the given number matches the enum matcher rules.
@@ -2309,7 +2319,6 @@
 }
 
 /// EnumMatcher for 'match write'
-/// @see src/tint/intrinsics.def:176:7
 class Write : public NumberMatcher {
  public:
   /// Checks whether the given number matches the enum matcher rules.
@@ -2335,7 +2344,6 @@
 }
 
 /// EnumMatcher for 'match read_write'
-/// @see src/tint/intrinsics.def:177:7
 class ReadWrite : public NumberMatcher {
  public:
   /// Checks whether the given number matches the enum matcher rules.
@@ -2361,7 +2369,6 @@
 }
 
 /// EnumMatcher for 'match function_private_workgroup'
-/// @see src/tint/intrinsics.def:179:7
 class FunctionPrivateWorkgroup : public NumberMatcher {
  public:
   /// Checks whether the given number matches the enum matcher rules.
@@ -2391,7 +2398,6 @@
 }
 
 /// EnumMatcher for 'match workgroup_or_storage'
-/// @see src/tint/intrinsics.def:183:7
 class WorkgroupOrStorage : public NumberMatcher {
  public:
   /// Checks whether the given number matches the enum matcher rules.
@@ -2420,7 +2426,6 @@
 }
 
 /// EnumMatcher for 'match storage'
-/// @see src/tint/intrinsics.def:186:7
 class Storage : public NumberMatcher {
  public:
   /// Checks whether the given number matches the enum matcher rules.
@@ -2509,6 +2514,8 @@
   ScalarNoU32 ScalarNoU32_;
   ScalarNoBool ScalarNoBool_;
   FiaFi32F16 FiaFi32F16_;
+  FiaFiu32 FiaFiu32_;
+  FaF32 FaF32_;
   FaF32F16 FaF32F16_;
   IaIu32 IaIu32_;
   Fiu32F16 Fiu32F16_;
@@ -2533,7 +2540,7 @@
   ~Matchers();
 
   /// The template types, types, and type matchers
-  TypeMatcher const* const type[66] = {
+  TypeMatcher const* const type[68] = {
     /* [0] */ &template_type_0_,
     /* [1] */ &template_type_1_,
     /* [2] */ &Bool_,
@@ -2592,14 +2599,16 @@
     /* [55] */ &ScalarNoU32_,
     /* [56] */ &ScalarNoBool_,
     /* [57] */ &FiaFi32F16_,
-    /* [58] */ &FaF32F16_,
-    /* [59] */ &IaIu32_,
-    /* [60] */ &Fiu32F16_,
-    /* [61] */ &Fiu32_,
-    /* [62] */ &Fi32F16_,
-    /* [63] */ &Fi32_,
-    /* [64] */ &F32F16_,
-    /* [65] */ &Iu32_,
+    /* [58] */ &FiaFiu32_,
+    /* [59] */ &FaF32_,
+    /* [60] */ &FaF32F16_,
+    /* [61] */ &IaIu32_,
+    /* [62] */ &Fiu32F16_,
+    /* [63] */ &Fiu32_,
+    /* [64] */ &Fi32F16_,
+    /* [65] */ &Fi32_,
+    /* [66] */ &F32F16_,
+    /* [67] */ &Iu32_,
   };
 
   /// The template numbers, and number matchers
@@ -5941,12 +5950,12 @@
   {
     /* [613] */
     /* usage */ ParameterUsage::kNone,
-    /* matcher indices */ &kMatcherIndices[4],
+    /* matcher indices */ &kMatcherIndices[1],
   },
   {
     /* [614] */
     /* usage */ ParameterUsage::kNone,
-    /* matcher indices */ &kMatcherIndices[4],
+    /* matcher indices */ &kMatcherIndices[1],
   },
   {
     /* [615] */
@@ -6631,12 +6640,12 @@
   {
     /* [751] */
     /* usage */ ParameterUsage::kNone,
-    /* matcher indices */ &kMatcherIndices[41],
+    /* matcher indices */ &kMatcherIndices[38],
   },
   {
     /* [752] */
     /* usage */ ParameterUsage::kNone,
-    /* matcher indices */ &kMatcherIndices[41],
+    /* matcher indices */ &kMatcherIndices[38],
   },
   {
     /* [753] */
@@ -7909,117 +7918,127 @@
   {
     /* [2] */
     /* name */ "T",
-    /* matcher index */ 7,
+    /* matcher index */ 8,
   },
   {
     /* [3] */
     /* name */ "U",
-    /* matcher index */ 52,
+    /* matcher index */ 53,
   },
   {
     /* [4] */
     /* name */ "T",
-    /* matcher index */ 8,
+    /* matcher index */ 5,
   },
   {
     /* [5] */
     /* name */ "U",
-    /* matcher index */ 53,
+    /* matcher index */ 54,
   },
   {
     /* [6] */
     /* name */ "T",
-    /* matcher index */ 5,
+    /* matcher index */ 6,
   },
   {
     /* [7] */
     /* name */ "U",
-    /* matcher index */ 54,
+    /* matcher index */ 55,
   },
   {
     /* [8] */
     /* name */ "T",
-    /* matcher index */ 6,
+    /* matcher index */ 7,
   },
   {
     /* [9] */
     /* name */ "U",
-    /* matcher index */ 55,
+    /* matcher index */ 52,
   },
   {
     /* [10] */
     /* name */ "T",
-    /* matcher index */ 65,
+    /* matcher index */ 67,
   },
   {
     /* [11] */
     /* name */ "T",
-    /* matcher index */ 58,
+    /* matcher index */ 60,
   },
   {
     /* [12] */
     /* name */ "T",
-    /* matcher index */ 64,
+    /* matcher index */ 59,
   },
   {
     /* [13] */
     /* name */ "T",
-    /* matcher index */ 61,
+    /* matcher index */ 66,
   },
   {
     /* [14] */
     /* name */ "T",
-    /* matcher index */ 50,
+    /* matcher index */ 58,
   },
   {
     /* [15] */
     /* name */ "T",
-    /* matcher index */ 51,
+    /* matcher index */ 63,
   },
   {
     /* [16] */
     /* name */ "T",
-    /* matcher index */ kNoMatcher,
+    /* matcher index */ 50,
   },
   {
     /* [17] */
     /* name */ "T",
-    /* matcher index */ 56,
+    /* matcher index */ kNoMatcher,
   },
   {
     /* [18] */
     /* name */ "T",
-    /* matcher index */ 53,
+    /* matcher index */ 51,
   },
   {
     /* [19] */
     /* name */ "T",
-    /* matcher index */ 52,
+    /* matcher index */ 56,
   },
   {
     /* [20] */
     /* name */ "T",
-    /* matcher index */ 55,
+    /* matcher index */ 53,
   },
   {
     /* [21] */
     /* name */ "T",
-    /* matcher index */ 54,
+    /* matcher index */ 52,
   },
   {
     /* [22] */
     /* name */ "T",
-    /* matcher index */ 60,
+    /* matcher index */ 55,
   },
   {
     /* [23] */
     /* name */ "T",
-    /* matcher index */ 57,
+    /* matcher index */ 54,
   },
   {
     /* [24] */
     /* name */ "T",
-    /* matcher index */ 59,
+    /* matcher index */ 62,
+  },
+  {
+    /* [25] */
+    /* name */ "T",
+    /* matcher index */ 57,
+  },
+  {
+    /* [26] */
+    /* name */ "T",
+    /* matcher index */ 61,
   },
 };
 
@@ -8082,7 +8101,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[918],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -8094,7 +8113,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[617],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -8106,7 +8125,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[917],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8118,7 +8137,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[621],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8130,7 +8149,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[916],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8142,7 +8161,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[625],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8154,7 +8173,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[915],
     /* return matcher indices */ &kMatcherIndices[112],
@@ -8166,7 +8185,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[629],
     /* return matcher indices */ &kMatcherIndices[112],
@@ -8178,7 +8197,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[914],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8190,7 +8209,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[633],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8202,7 +8221,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[913],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8214,7 +8233,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[637],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8226,7 +8245,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[912],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8238,7 +8257,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[911],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8250,7 +8269,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[643],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8262,7 +8281,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[910],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8274,7 +8293,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[647],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8286,7 +8305,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[909],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8298,7 +8317,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[651],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8310,7 +8329,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[835],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8322,7 +8341,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[655],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8334,7 +8353,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[907],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8346,7 +8365,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[3],
     /* parameters */ &kParameters[905],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -8358,7 +8377,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[3],
     /* parameters */ &kParameters[904],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8370,7 +8389,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[3],
     /* parameters */ &kParameters[903],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8382,7 +8401,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[3],
     /* parameters */ &kParameters[902],
     /* return matcher indices */ &kMatcherIndices[112],
@@ -8394,7 +8413,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[901],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -8406,7 +8425,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8418,7 +8437,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[955],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8430,7 +8449,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[956],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8442,7 +8461,7 @@
     /* num parameters */ 4,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[399],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8454,7 +8473,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[564],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8466,7 +8485,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[573],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8478,7 +8497,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[576],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8490,7 +8509,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[605],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8502,7 +8521,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[603],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8514,7 +8533,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[601],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8526,7 +8545,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1003],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8538,7 +8557,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[965],
     /* return matcher indices */ &kMatcherIndices[148],
@@ -8550,7 +8569,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[6],
+    /* template types */ &kTemplateTypes[4],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[966],
     /* return matcher indices */ &kMatcherIndices[152],
@@ -8562,7 +8581,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[8],
+    /* template types */ &kTemplateTypes[6],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[967],
     /* return matcher indices */ &kMatcherIndices[158],
@@ -8586,7 +8605,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[510],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8598,7 +8617,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[507],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8610,7 +8629,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[351],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8622,7 +8641,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[347],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8634,7 +8653,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[230],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8646,7 +8665,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[495],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8658,7 +8677,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[331],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8670,7 +8689,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[489],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8682,7 +8701,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[327],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8694,7 +8713,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[474],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8706,7 +8725,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[323],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8718,7 +8737,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[319],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8730,7 +8749,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[165],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8742,7 +8761,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[462],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8754,7 +8773,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[339],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8766,7 +8785,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[315],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8778,7 +8797,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[265],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8790,7 +8809,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[260],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8802,7 +8821,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[132],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8814,7 +8833,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[299],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8826,7 +8845,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[205],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8838,7 +8857,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[295],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8850,7 +8869,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[285],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8862,7 +8881,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[303],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8874,7 +8893,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[275],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8886,7 +8905,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[270],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8898,7 +8917,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[90],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8910,7 +8929,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[307],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8922,7 +8941,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[255],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -8934,7 +8953,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[471],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -8946,7 +8965,7 @@
     /* num parameters */ 4,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[431],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8958,7 +8977,7 @@
     /* num parameters */ 5,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[250],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8970,7 +8989,7 @@
     /* num parameters */ 5,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[215],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8982,7 +9001,7 @@
     /* num parameters */ 6,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[96],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -8994,7 +9013,7 @@
     /* num parameters */ 4,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[407],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -9006,7 +9025,7 @@
     /* num parameters */ 5,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[170],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -9018,7 +9037,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[558],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9030,7 +9049,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[387],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9042,7 +9061,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[379],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9054,7 +9073,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[160],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9066,7 +9085,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[585],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9078,7 +9097,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[375],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9090,7 +9109,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[486],
     /* return matcher indices */ nullptr,
@@ -9102,7 +9121,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[492],
     /* return matcher indices */ nullptr,
@@ -9114,7 +9133,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[335],
     /* return matcher indices */ nullptr,
@@ -9126,7 +9145,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[498],
     /* return matcher indices */ nullptr,
@@ -9138,7 +9157,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[501],
     /* return matcher indices */ nullptr,
@@ -9150,7 +9169,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[504],
     /* return matcher indices */ nullptr,
@@ -9162,7 +9181,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[311],
     /* return matcher indices */ nullptr,
@@ -9174,7 +9193,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[513],
     /* return matcher indices */ nullptr,
@@ -9186,7 +9205,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[516],
     /* return matcher indices */ nullptr,
@@ -9198,7 +9217,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[465],
     /* return matcher indices */ nullptr,
@@ -9210,7 +9229,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[359],
     /* return matcher indices */ nullptr,
@@ -9222,7 +9241,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[519],
     /* return matcher indices */ nullptr,
@@ -9234,7 +9253,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[116],
@@ -9246,7 +9265,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[944],
     /* return matcher indices */ &kMatcherIndices[116],
@@ -9258,7 +9277,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[945],
     /* return matcher indices */ &kMatcherIndices[116],
@@ -9270,7 +9289,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[588],
     /* return matcher indices */ &kMatcherIndices[116],
@@ -9282,7 +9301,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[609],
     /* return matcher indices */ &kMatcherIndices[116],
@@ -9294,7 +9313,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[607],
     /* return matcher indices */ &kMatcherIndices[116],
@@ -9306,7 +9325,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[949],
     /* return matcher indices */ &kMatcherIndices[108],
@@ -9318,7 +9337,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[950],
     /* return matcher indices */ &kMatcherIndices[110],
@@ -9330,7 +9349,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[6],
+    /* template types */ &kTemplateTypes[4],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[951],
     /* return matcher indices */ &kMatcherIndices[112],
@@ -9342,7 +9361,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[8],
+    /* template types */ &kTemplateTypes[6],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[952],
     /* return matcher indices */ &kMatcherIndices[118],
@@ -9366,7 +9385,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[880],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9378,7 +9397,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[879],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9390,7 +9409,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[878],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9402,7 +9421,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[877],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9414,7 +9433,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[876],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9426,7 +9445,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[875],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9438,7 +9457,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[874],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9450,7 +9469,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[873],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9462,7 +9481,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[872],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9474,7 +9493,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[871],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -9486,7 +9505,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[727],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -9498,7 +9517,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[725],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -9510,7 +9529,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[723],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -9522,7 +9541,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[721],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -9534,7 +9553,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[719],
     /* return matcher indices */ &kMatcherIndices[10],
@@ -9546,7 +9565,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[717],
     /* return matcher indices */ &kMatcherIndices[10],
@@ -9558,7 +9577,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[1],
     /* parameters */ &kParameters[715],
     /* return matcher indices */ &kMatcherIndices[77],
@@ -9570,7 +9589,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[1],
     /* parameters */ &kParameters[713],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -9582,7 +9601,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 3,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[0],
     /* parameters */ &kParameters[711],
     /* return matcher indices */ &kMatcherIndices[22],
@@ -9594,7 +9613,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[522],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -9606,7 +9625,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[528],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -9618,7 +9637,7 @@
     /* num parameters */ 4,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[363],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -9630,7 +9649,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[531],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -9642,7 +9661,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[549],
     /* return matcher indices */ &kMatcherIndices[122],
@@ -9654,7 +9673,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[552],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -9666,7 +9685,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[383],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -9678,7 +9697,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[555],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -9690,7 +9709,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[783],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9702,7 +9721,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[114],
@@ -9714,7 +9733,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[935],
     /* return matcher indices */ &kMatcherIndices[114],
@@ -9726,7 +9745,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[936],
     /* return matcher indices */ &kMatcherIndices[114],
@@ -9738,7 +9757,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[14],
+    /* template types */ &kTemplateTypes[16],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[611],
     /* return matcher indices */ &kMatcherIndices[114],
@@ -9750,7 +9769,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[938],
     /* return matcher indices */ &kMatcherIndices[136],
@@ -9762,7 +9781,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[939],
     /* return matcher indices */ &kMatcherIndices[134],
@@ -9774,7 +9793,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[6],
+    /* template types */ &kTemplateTypes[4],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[940],
     /* return matcher indices */ &kMatcherIndices[132],
@@ -9786,7 +9805,7 @@
     /* num parameters */ 1,
     /* num template types */ 2,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[8],
+    /* template types */ &kTemplateTypes[6],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[941],
     /* return matcher indices */ &kMatcherIndices[130],
@@ -9810,7 +9829,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[180],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9822,7 +9841,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[108],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9834,7 +9853,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[102],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9846,7 +9865,7 @@
     /* num parameters */ 7,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[65],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9858,7 +9877,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[235],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9870,7 +9889,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[78],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9882,7 +9901,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[245],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9894,7 +9913,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[120],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9906,7 +9925,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[343],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9918,7 +9937,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[225],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9930,7 +9949,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[150],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9942,7 +9961,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[144],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9954,7 +9973,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[439],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9966,7 +9985,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[200],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9978,7 +9997,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[435],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -9990,7 +10009,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[280],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -10002,7 +10021,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[226],
@@ -10014,7 +10033,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[922],
     /* return matcher indices */ &kMatcherIndices[226],
@@ -10050,7 +10069,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[908],
     /* return matcher indices */ &kMatcherIndices[230],
@@ -10062,7 +10081,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[906],
     /* return matcher indices */ &kMatcherIndices[228],
@@ -10074,7 +10093,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[419],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10086,7 +10105,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[240],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10098,7 +10117,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[220],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10110,7 +10129,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[138],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10122,7 +10141,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[403],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10134,7 +10153,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[290],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10146,7 +10165,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[180],
@@ -10158,7 +10177,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[982],
     /* return matcher indices */ &kMatcherIndices[180],
@@ -10194,7 +10213,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[985],
     /* return matcher indices */ &kMatcherIndices[184],
@@ -10206,7 +10225,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[986],
     /* return matcher indices */ &kMatcherIndices[182],
@@ -10218,7 +10237,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[164],
@@ -10230,7 +10249,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[970],
     /* return matcher indices */ &kMatcherIndices[164],
@@ -10266,7 +10285,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[973],
     /* return matcher indices */ &kMatcherIndices[170],
@@ -10278,7 +10297,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[974],
     /* return matcher indices */ &kMatcherIndices[166],
@@ -10290,7 +10309,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[395],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10302,7 +10321,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[195],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10314,7 +10333,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[155],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10326,7 +10345,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[72],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10338,7 +10357,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[371],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10350,7 +10369,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[175],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -10362,7 +10381,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[367],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -10374,7 +10393,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[185],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -10386,7 +10405,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[190],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -10398,7 +10417,7 @@
     /* num parameters */ 6,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[126],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -10410,7 +10429,7 @@
     /* num parameters */ 4,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[355],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -10422,7 +10441,7 @@
     /* num parameters */ 5,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[210],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -10434,7 +10453,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[172],
@@ -10446,7 +10465,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[976],
     /* return matcher indices */ &kMatcherIndices[172],
@@ -10482,7 +10501,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[979],
     /* return matcher indices */ &kMatcherIndices[178],
@@ -10494,7 +10513,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[980],
     /* return matcher indices */ &kMatcherIndices[176],
@@ -10506,7 +10525,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[202],
@@ -10518,7 +10537,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[987],
     /* return matcher indices */ &kMatcherIndices[202],
@@ -10554,7 +10573,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[969],
     /* return matcher indices */ &kMatcherIndices[206],
@@ -10566,7 +10585,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[954],
     /* return matcher indices */ &kMatcherIndices[204],
@@ -10578,7 +10597,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[208],
@@ -10590,7 +10609,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[943],
     /* return matcher indices */ &kMatcherIndices[208],
@@ -10626,7 +10645,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[928],
     /* return matcher indices */ &kMatcherIndices[220],
@@ -10638,7 +10657,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[925],
     /* return matcher indices */ &kMatcherIndices[218],
@@ -10650,7 +10669,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[104],
@@ -10662,7 +10681,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1000],
     /* return matcher indices */ &kMatcherIndices[104],
@@ -10698,7 +10717,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[999],
     /* return matcher indices */ &kMatcherIndices[200],
@@ -10710,7 +10729,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[993],
     /* return matcher indices */ &kMatcherIndices[198],
@@ -10722,7 +10741,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[192],
@@ -10734,7 +10753,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[994],
     /* return matcher indices */ &kMatcherIndices[192],
@@ -10770,7 +10789,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[997],
     /* return matcher indices */ &kMatcherIndices[196],
@@ -10782,7 +10801,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[998],
     /* return matcher indices */ &kMatcherIndices[194],
@@ -10794,7 +10813,7 @@
     /* num parameters */ 0,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[186],
@@ -10806,7 +10825,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[988],
     /* return matcher indices */ &kMatcherIndices[186],
@@ -10842,7 +10861,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[4],
+    /* template types */ &kTemplateTypes[2],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[991],
     /* return matcher indices */ &kMatcherIndices[190],
@@ -10854,7 +10873,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[2],
+    /* template types */ &kTemplateTypes[8],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[992],
     /* return matcher indices */ &kMatcherIndices[188],
@@ -10866,7 +10885,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[737],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -10878,7 +10897,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[735],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -10890,7 +10909,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[733],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -10902,7 +10921,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[731],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -10914,7 +10933,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[729],
     /* return matcher indices */ &kMatcherIndices[10],
@@ -10926,7 +10945,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[885],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -10938,7 +10957,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[884],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -10950,7 +10969,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[883],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -10962,7 +10981,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[882],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -10974,7 +10993,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[3],
     /* parameters */ &kParameters[881],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -10986,7 +11005,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[749],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -10998,7 +11017,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[747],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11010,7 +11029,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[745],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11022,7 +11041,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[743],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11034,7 +11053,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[12],
+    /* template types */ &kTemplateTypes[13],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[741],
     /* return matcher indices */ &kMatcherIndices[10],
@@ -11046,7 +11065,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[701],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -11058,7 +11077,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[699],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11070,7 +11089,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[695],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11082,7 +11101,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[693],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11094,7 +11113,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[687],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -11106,7 +11125,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[685],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -11142,7 +11161,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[679],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -11154,7 +11173,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[677],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -11190,7 +11209,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[709],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -11202,7 +11221,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[707],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11214,7 +11233,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[705],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11226,7 +11245,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[781],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11238,7 +11257,7 @@
     /* num parameters */ 0,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -11250,7 +11269,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[920],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -11262,7 +11281,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[21],
+    /* template types */ &kTemplateTypes[23],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[921],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -11274,7 +11293,7 @@
     /* num parameters */ 0,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -11286,7 +11305,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[932],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -11298,7 +11317,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[17],
+    /* template types */ &kTemplateTypes[19],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[933],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -11310,7 +11329,7 @@
     /* num parameters */ 0,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[111],
@@ -11322,7 +11341,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[929],
     /* return matcher indices */ &kMatcherIndices[111],
@@ -11334,7 +11353,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[18],
+    /* template types */ &kTemplateTypes[20],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[930],
     /* return matcher indices */ &kMatcherIndices[111],
@@ -11346,7 +11365,7 @@
     /* num parameters */ 0,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11358,7 +11377,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[926],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11370,7 +11389,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[19],
+    /* template types */ &kTemplateTypes[21],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[927],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11382,7 +11401,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[18],
+    /* template types */ &kTemplateTypes[20],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[540],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -11394,7 +11413,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[18],
+    /* template types */ &kTemplateTypes[20],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[543],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11406,7 +11425,7 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[18],
+    /* template types */ &kTemplateTypes[20],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[546],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11418,7 +11437,7 @@
     /* num parameters */ 0,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -11430,7 +11449,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[923],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -11442,7 +11461,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[20],
+    /* template types */ &kTemplateTypes[22],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[924],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -11454,7 +11473,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[477],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11466,7 +11485,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[480],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11478,7 +11497,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[483],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11490,7 +11509,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[24],
+    /* template types */ &kTemplateTypes[26],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[860],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -11502,7 +11521,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[24],
+    /* template types */ &kTemplateTypes[26],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[861],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11514,7 +11533,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[798],
     /* return matcher indices */ &kMatcherIndices[241],
@@ -11526,7 +11545,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[810],
     /* return matcher indices */ &kMatcherIndices[174],
@@ -11538,7 +11557,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[822],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11550,7 +11569,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[823],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11562,7 +11581,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[800],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11574,7 +11593,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[799],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11586,7 +11605,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[826],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11598,7 +11617,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[830],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11634,7 +11653,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[846],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11646,7 +11665,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[848],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11658,7 +11677,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[779],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11670,7 +11689,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[777],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11682,7 +11701,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[849],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11694,7 +11713,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[850],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11706,7 +11725,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[851],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11718,7 +11737,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[852],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11730,7 +11749,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[853],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11742,7 +11761,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[854],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11754,7 +11773,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[763],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -11766,7 +11785,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[761],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11778,7 +11797,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[759],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -11790,7 +11809,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[757],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -11802,7 +11821,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[450],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11814,7 +11833,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[447],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11826,7 +11845,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[855],
     /* return matcher indices */ &kMatcherIndices[240],
@@ -11838,7 +11857,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[856],
     /* return matcher indices */ &kMatcherIndices[138],
@@ -11850,7 +11869,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[802],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11862,7 +11881,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[801],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11874,7 +11893,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[824],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11886,7 +11905,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[825],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11946,7 +11965,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[808],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11958,7 +11977,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[807],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11970,7 +11989,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[886],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -11982,7 +12001,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[809],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -11994,7 +12013,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[739],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12006,7 +12025,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[703],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12018,7 +12037,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[887],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12030,7 +12049,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[888],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12042,7 +12061,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[811],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12054,7 +12073,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[1001],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12066,7 +12085,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[813],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12078,7 +12097,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[812],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12114,7 +12133,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[891],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12126,7 +12145,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[892],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12138,7 +12157,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[815],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12150,7 +12169,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[814],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12162,7 +12181,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[893],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12174,7 +12193,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[894],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12186,7 +12205,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[895],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12198,7 +12217,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[896],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12210,7 +12229,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[897],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12222,7 +12241,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[898],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12234,7 +12253,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[567],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12246,7 +12265,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[570],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12258,7 +12277,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[899],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12270,7 +12289,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[900],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12282,7 +12301,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[671],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12294,7 +12313,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[669],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12330,7 +12349,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[919],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12342,7 +12361,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[797],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12354,7 +12373,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[984],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12366,7 +12385,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[978],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12378,7 +12397,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[817],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12390,7 +12409,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[816],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12402,7 +12421,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[964],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12414,7 +12433,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[963],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12426,7 +12445,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[819],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12438,7 +12457,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[818],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12474,7 +12493,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[821],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12486,7 +12505,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[820],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12498,7 +12517,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[635],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -12510,7 +12529,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[631],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -12522,7 +12541,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[641],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -12534,7 +12553,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[639],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -12546,7 +12565,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[649],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -12558,7 +12577,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[645],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -12570,7 +12589,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[787],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12582,7 +12601,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[789],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12594,7 +12613,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[829],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12606,7 +12625,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[828],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12618,7 +12637,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1002],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -12630,7 +12649,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[996],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -12690,7 +12709,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[870],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -12702,7 +12721,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[869],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -12738,7 +12757,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[657],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -12750,7 +12769,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[22],
+    /* template types */ &kTemplateTypes[24],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[653],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -12762,7 +12781,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[839],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12774,7 +12793,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[838],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12786,7 +12805,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[841],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12798,7 +12817,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[840],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12810,31 +12829,31 @@
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[14],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[537],
     /* return matcher indices */ &kMatcherIndices[1],
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
-    /* const eval */ nullptr,
+    /* const eval */ &ConstEval::clamp,
   },
   {
     /* [395] */
     /* num parameters */ 3,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[14],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[534],
     /* return matcher indices */ &kMatcherIndices[38],
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
-    /* const eval */ nullptr,
+    /* const eval */ &ConstEval::clamp,
   },
   {
     /* [396] */
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[843],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12846,7 +12865,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[842],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12858,7 +12877,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[845],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12870,7 +12889,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[844],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12880,33 +12899,33 @@
   {
     /* [400] */
     /* num parameters */ 2,
-    /* num template types */ 0,
+    /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[12],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[613],
-    /* return matcher indices */ &kMatcherIndices[4],
+    /* return matcher indices */ &kMatcherIndices[1],
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
-    /* const eval */ nullptr,
+    /* const eval */ &ConstEval::atan2,
   },
   {
     /* [401] */
     /* num parameters */ 2,
-    /* num template types */ 0,
+    /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[12],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[751],
-    /* return matcher indices */ &kMatcherIndices[41],
+    /* return matcher indices */ &kMatcherIndices[38],
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
-    /* const eval */ nullptr,
+    /* const eval */ &ConstEval::atan2,
   },
   {
     /* [402] */
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[659],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -12918,7 +12937,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[599],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -12930,7 +12949,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[663],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -12942,7 +12961,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[15],
+    /* template types */ &kTemplateTypes[18],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[661],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -12954,7 +12973,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[934],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12966,7 +12985,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[931],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -12978,7 +12997,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[957],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -12990,7 +13009,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[946],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -13026,7 +13045,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[959],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -13038,7 +13057,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[958],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -13050,7 +13069,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[975],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -13062,7 +13081,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[971],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -13074,7 +13093,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[981],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -13086,7 +13105,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[977],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -13098,7 +13117,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[989],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -13110,7 +13129,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[983],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -13122,7 +13141,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[995],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -13134,7 +13153,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[990],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -13146,7 +13165,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[23],
+    /* template types */ &kTemplateTypes[25],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[862],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -13158,7 +13177,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[23],
+    /* template types */ &kTemplateTypes[25],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[863],
     /* return matcher indices */ &kMatcherIndices[38],
@@ -13170,7 +13189,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[858],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -13182,7 +13201,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[859],
     /* return matcher indices */ &kMatcherIndices[50],
@@ -13326,7 +13345,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[667],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -13338,7 +13357,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[665],
     /* return matcher indices */ &kMatcherIndices[16],
@@ -13374,7 +13393,7 @@
     /* num parameters */ 0,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ nullptr,
@@ -13386,7 +13405,7 @@
     /* num parameters */ 0,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[1004],
     /* return matcher indices */ nullptr,
@@ -13398,7 +13417,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[937],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -13410,7 +13429,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[947],
     /* return matcher indices */ &kMatcherIndices[128],
@@ -13422,7 +13441,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[948],
     /* return matcher indices */ &kMatcherIndices[136],
@@ -13434,7 +13453,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[961],
     /* return matcher indices */ &kMatcherIndices[136],
@@ -13446,7 +13465,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[962],
     /* return matcher indices */ &kMatcherIndices[136],
@@ -13458,7 +13477,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 2,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[5],
     /* parameters */ &kParameters[972],
     /* return matcher indices */ &kMatcherIndices[26],
@@ -13470,7 +13489,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[525],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -13482,7 +13501,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[697],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -13494,7 +13513,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[868],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -13506,7 +13525,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[867],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -13518,7 +13537,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[866],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -13530,7 +13549,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[865],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -13542,7 +13561,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[857],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -13554,7 +13573,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[785],
     /* return matcher indices */ &kMatcherIndices[108],
@@ -13566,7 +13585,7 @@
     /* num parameters */ 3,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[453],
     /* return matcher indices */ &kMatcherIndices[41],
@@ -13578,7 +13597,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[795],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -13590,7 +13609,7 @@
     /* num parameters */ 2,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[793],
     /* return matcher indices */ &kMatcherIndices[45],
@@ -13602,7 +13621,7 @@
     /* num parameters */ 2,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[13],
+    /* template types */ &kTemplateTypes[15],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[791],
     /* return matcher indices */ &kMatcherIndices[1],
@@ -13614,7 +13633,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[6],
     /* parameters */ &kParameters[827],
     /* return matcher indices */ &kMatcherIndices[4],
@@ -13626,7 +13645,7 @@
     /* num parameters */ 1,
     /* num template types */ 1,
     /* num template numbers */ 1,
-    /* template types */ &kTemplateTypes[16],
+    /* template types */ &kTemplateTypes[17],
     /* template numbers */ &kTemplateNumbers[8],
     /* parameters */ &kParameters[960],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -13638,7 +13657,7 @@
     /* num parameters */ 1,
     /* num template types */ 0,
     /* num template numbers */ 0,
-    /* template types */ &kTemplateTypes[25],
+    /* template types */ &kTemplateTypes[27],
     /* template numbers */ &kTemplateNumbers[10],
     /* parameters */ &kParameters[864],
     /* return matcher indices */ &kMatcherIndices[46],
@@ -13712,8 +13731,8 @@
   },
   {
     /* [9] */
-    /* fn atan2(f32, f32) -> f32 */
-    /* fn atan2<N : num>(vec<N, f32>, vec<N, f32>) -> vec<N, f32> */
+    /* fn atan2<T : fa_f32>(T, T) -> T */
+    /* fn atan2<N : num, T : fa_f32>(vec<N, T>, vec<N, T>) -> vec<N, T> */
     /* num overloads */ 2,
     /* overloads */ &kOverloads[400],
   },
@@ -13733,8 +13752,8 @@
   },
   {
     /* [12] */
-    /* fn clamp<T : fiu32>(T, T, T) -> T */
-    /* fn clamp<N : num, T : fiu32>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* fn clamp<T : fia_fiu32>(T, T, T) -> T */
+    /* fn clamp<N : num, T : fia_fiu32>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
     /* num overloads */ 2,
     /* overloads */ &kOverloads[394],
   },
diff --git a/src/tint/resolver/intrinsic_table.inl.tmpl b/src/tint/resolver/intrinsic_table.inl.tmpl
index e78e5cb..750c29f 100644
--- a/src/tint/resolver/intrinsic_table.inl.tmpl
+++ b/src/tint/resolver/intrinsic_table.inl.tmpl
@@ -3,6 +3,9 @@
 Template file for use with tools/src/cmd/gen to generate builtin_table.inl
 Used by BuiltinTable.cc for builtin overload resolution.
 
+To update the generated file, run:
+    ./tools/run gen
+
 See:
 * tools/src/cmd/gen for structures used by this template
 * https://golang.org/pkg/text/template/ for documentation on the template syntax
@@ -179,7 +182,6 @@
 {{- $class := PascalCase .Name -}}
 /// TypeMatcher for 'type {{.Name}}'
 {{- if .Decl.Source.S.Filepath  }}
-/// @see {{.Decl.Source}}
 {{- end  }}
 class {{$class}} : public TypeMatcher {
  public:
@@ -234,7 +236,6 @@
 {{- $class := PascalCase .Name -}}
 /// TypeMatcher for 'match {{.Name}}'
 {{- if .Decl.Source.S.Filepath  }}
-/// @see {{.Decl.Source}}
 {{- end  }}
 class {{$class}} : public TypeMatcher {
  public:
@@ -282,7 +283,6 @@
 {{- $enum := PascalCase .Enum.Name -}}
 /// EnumMatcher for 'match {{.Name}}'
 {{- if .Decl.Source.S.Filepath  }}
-/// @see {{.Decl.Source}}
 {{- end  }}
 class {{$class}} : public NumberMatcher {
  public:
diff --git a/src/tint/resolver/intrinsic_table_test.cc b/src/tint/resolver/intrinsic_table_test.cc
index e8cb206..9301386 100644
--- a/src/tint/resolver/intrinsic_table_test.cc
+++ b/src/tint/resolver/intrinsic_table_test.cc
@@ -1075,14 +1075,14 @@
     IntrinsicTableAbstractTernaryTest,
     testing::Values(  // clang-format off
 //           result  | param a | param b | param c |  arg a  |  arg b  |  arg c
-Case::Create<f32,      f32,      f32,      f32,      AFloat,   AFloat,   AFloat>(),
-Case::Create<f32,      f32,      f32,      f32,      AFloat,   AFloat,   AInt>(),
-Case::Create<f32,      f32,      f32,      f32,      AFloat,   AInt,     AFloat>(),
-Case::Create<f32,      f32,      f32,      f32,      AFloat,   AInt,     AInt>(),
-Case::Create<f32,      f32,      f32,      f32,      AInt,     AFloat,   AFloat>(),
-Case::Create<f32,      f32,      f32,      f32,      AInt,     AFloat,   AInt>(),
-Case::Create<f32,      f32,      f32,      f32,      AInt,     AInt,     AFloat>(),
-Case::Create<i32,      i32,      i32,      i32,      AInt,     AInt,     AInt>()
+Case::Create<AFloat,    AFloat,  AFloat,   AFloat,   AFloat,   AFloat,   AFloat>(),
+Case::Create<AFloat,    AFloat,  AFloat,   AFloat,   AFloat,   AFloat,   AInt>(),
+Case::Create<AFloat,    AFloat,  AFloat,   AFloat,   AFloat,   AInt,     AFloat>(),
+Case::Create<AFloat,    AFloat,  AFloat,   AFloat,   AFloat,   AInt,     AInt>(),
+Case::Create<AFloat,    AFloat,  AFloat,   AFloat,   AInt,     AFloat,   AFloat>(),
+Case::Create<AFloat,    AFloat,  AFloat,   AFloat,   AInt,     AFloat,   AInt>(),
+Case::Create<AFloat,    AFloat,  AFloat,   AFloat,   AInt,     AInt,     AFloat>(),
+Case::Create<AInt,      AInt,    AInt,     AInt,     AInt,     AInt,     AInt>()
         // clang-format on
         ));
 
@@ -1091,14 +1091,14 @@
     IntrinsicTableAbstractTernaryTest,
     testing::Values(  // clang-format off
 //           result  | param a | param b | param c |  arg a  |  arg b  |  arg c
-Case::Create<f32V,     f32V,     f32V,     f32V,     AFloatV,  AFloatV,  AFloatV>(),
-Case::Create<f32V,     f32V,     f32V,     f32V,     AFloatV,  AFloatV,  AIntV>(),
-Case::Create<f32V,     f32V,     f32V,     f32V,     AFloatV,  AIntV,    AFloatV>(),
-Case::Create<f32V,     f32V,     f32V,     f32V,     AFloatV,  AIntV,    AIntV>(),
-Case::Create<f32V,     f32V,     f32V,     f32V,     AIntV,    AFloatV,  AFloatV>(),
-Case::Create<f32V,     f32V,     f32V,     f32V,     AIntV,    AFloatV,  AIntV>(),
-Case::Create<f32V,     f32V,     f32V,     f32V,     AIntV,    AIntV,    AFloatV>(),
-Case::Create<i32V,     i32V,     i32V,     i32V,     AIntV,    AIntV,    AIntV>()
+Case::Create<AFloatV,  AFloatV,  AFloatV,  AFloatV,  AFloatV,  AFloatV,  AFloatV>(),
+Case::Create<AFloatV,  AFloatV,  AFloatV,  AFloatV,  AFloatV,  AFloatV,  AIntV>(),
+Case::Create<AFloatV,  AFloatV,  AFloatV,  AFloatV,  AFloatV,  AIntV,    AFloatV>(),
+Case::Create<AFloatV,  AFloatV,  AFloatV,  AFloatV,  AFloatV,  AIntV,    AIntV>(),
+Case::Create<AFloatV,  AFloatV,  AFloatV,  AFloatV,  AIntV,    AFloatV,  AFloatV>(),
+Case::Create<AFloatV,  AFloatV,  AFloatV,  AFloatV,  AIntV,    AFloatV,  AIntV>(),
+Case::Create<AFloatV,  AFloatV,  AFloatV,  AFloatV,  AIntV,    AIntV,    AFloatV>(),
+Case::Create<AIntV,    AIntV,    AIntV,    AIntV,    AIntV,    AIntV,    AIntV>()
         // clang-format on
         ));
 
@@ -1270,6 +1270,68 @@
         // clang-format on
         ));
 
+struct IntrinsicTableAbstractTernaryTest_NonConstEval : public ResolverTestWithParam<Case> {
+    std::unique_ptr<IntrinsicTable> table = IntrinsicTable::Create(*this);
+};
+
+TEST_P(IntrinsicTableAbstractTernaryTest_NonConstEval, MatchMix) {
+    auto* arg_a = GetParam().arg_a(*this);
+    auto* arg_b = GetParam().arg_b(*this);
+    auto* arg_c = GetParam().arg_c(*this);
+    auto builtin =
+        table->Lookup(sem::BuiltinType::kMix, utils::Vector{arg_a, arg_b, arg_c}, Source{{12, 34}});
+
+    bool matched = builtin.sem != nullptr;
+    bool expected_match = GetParam().expected_match;
+    EXPECT_EQ(matched, expected_match) << Diagnostics().str();
+
+    auto* result = builtin.sem ? builtin.sem->ReturnType() : nullptr;
+    auto* expected_result = GetParam().expected_result(*this);
+    EXPECT_TYPE(result, expected_result);
+
+    auto* param_a = builtin.sem ? builtin.sem->Parameters()[0]->Type() : nullptr;
+    auto* expected_param_a = GetParam().expected_param_a(*this);
+    EXPECT_TYPE(param_a, expected_param_a);
+
+    auto* param_b = builtin.sem ? builtin.sem->Parameters()[1]->Type() : nullptr;
+    auto* expected_param_b = GetParam().expected_param_b(*this);
+    EXPECT_TYPE(param_b, expected_param_b);
+
+    auto* param_c = builtin.sem ? builtin.sem->Parameters()[2]->Type() : nullptr;
+    auto* expected_param_c = GetParam().expected_param_c(*this);
+    EXPECT_TYPE(param_c, expected_param_c);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    AFloat_f32,
+    IntrinsicTableAbstractTernaryTest_NonConstEval,
+    testing::Values(  // clang-format off
+                      //           result  | param a | param b | param c |  arg a  |  arg b  |  arg c
+        Case::Create<f32,      f32,      f32,      f32,      AFloat,   AFloat,   AFloat>(),
+        Case::Create<f32,      f32,      f32,      f32,      AFloat,   AFloat,   f32>(),
+        Case::Create<f32,      f32,      f32,      f32,      AFloat,   f32,      AFloat>(),
+        Case::Create<f32,      f32,      f32,      f32,      AFloat,   f32,      f32>(),
+        Case::Create<f32,      f32,      f32,      f32,      f32,      AFloat,   AFloat>(),
+        Case::Create<f32,      f32,      f32,      f32,      f32,      AFloat,   f32>(),
+        Case::Create<f32,      f32,      f32,      f32,      f32,      f32,      AFloat>()
+        // clang-format on
+        ));
+
+INSTANTIATE_TEST_SUITE_P(
+    VecAFloat_Vecf32,
+    IntrinsicTableAbstractTernaryTest_NonConstEval,
+    testing::Values(  // clang-format off
+                      //           result  | param a | param b | param c |  arg a  |  arg b  |  arg c
+        Case::Create<f32V,     f32V,     f32V,     f32V,     AFloatV,  AFloatV,  AFloatV>(),
+        Case::Create<f32V,     f32V,     f32V,     f32V,     AFloatV,  AFloatV,  f32V>(),
+        Case::Create<f32V,     f32V,     f32V,     f32V,     AFloatV,  f32V,     AFloatV>(),
+        Case::Create<f32V,     f32V,     f32V,     f32V,     AFloatV,  f32V,     f32V>(),
+        Case::Create<f32V,     f32V,     f32V,     f32V,     f32V,     AFloatV,  AFloatV>(),
+        Case::Create<f32V,     f32V,     f32V,     f32V,     f32V,     AFloatV,  f32V>(),
+        Case::Create<f32V,     f32V,     f32V,     f32V,     f32V,     f32V,     AFloatV> ()
+        // clang-format on
+        ));
+
 }  // namespace AbstractTernaryTests
 
 }  // namespace
diff --git a/src/tint/resolver/pipeline_overridable_constant_test.cc b/src/tint/resolver/override_test.cc
similarity index 71%
rename from src/tint/resolver/pipeline_overridable_constant_test.cc
rename to src/tint/resolver/override_test.cc
index 3614500..f1e13e9 100644
--- a/src/tint/resolver/pipeline_overridable_constant_test.cc
+++ b/src/tint/resolver/override_test.cc
@@ -21,23 +21,23 @@
 namespace tint::resolver {
 namespace {
 
-class ResolverPipelineOverridableConstantTest : public ResolverTest {
+class ResolverOverrideTest : public ResolverTest {
   protected:
     /// Verify that the AST node `var` was resolved to an overridable constant
     /// with an ID equal to `id`.
     /// @param var the overridable constant AST node
     /// @param id the expected constant ID
-    void ExpectConstantId(const ast::Variable* var, uint16_t id) {
+    void ExpectOverrideId(const ast::Variable* var, uint16_t id) {
         auto* sem = Sem().Get<sem::GlobalVariable>(var);
         ASSERT_NE(sem, nullptr);
         EXPECT_EQ(sem->Declaration(), var);
         EXPECT_TRUE(sem->Declaration()->Is<ast::Override>());
-        EXPECT_EQ(sem->ConstantId(), id);
+        EXPECT_EQ(sem->OverrideId().value, id);
         EXPECT_FALSE(sem->ConstantValue());
     }
 };
 
-TEST_F(ResolverPipelineOverridableConstantTest, NonOverridable) {
+TEST_F(ResolverOverrideTest, NonOverridable) {
     auto* a = GlobalConst("a", ty.f32(), Expr(1_f));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -49,23 +49,23 @@
     EXPECT_TRUE(sem_a->ConstantValue());
 }
 
-TEST_F(ResolverPipelineOverridableConstantTest, WithId) {
+TEST_F(ResolverOverrideTest, WithId) {
     auto* a = Override("a", ty.f32(), Expr(1_f), {Id(7u)});
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-    ExpectConstantId(a, 7u);
+    ExpectOverrideId(a, 7u);
 }
 
-TEST_F(ResolverPipelineOverridableConstantTest, WithoutId) {
+TEST_F(ResolverOverrideTest, WithoutId) {
     auto* a = Override("a", ty.f32(), Expr(1_f));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-    ExpectConstantId(a, 0u);
+    ExpectOverrideId(a, 0u);
 }
 
-TEST_F(ResolverPipelineOverridableConstantTest, WithAndWithoutIds) {
+TEST_F(ResolverOverrideTest, WithAndWithoutIds) {
     std::vector<ast::Variable*> variables;
     auto* a = Override("a", ty.f32(), Expr(1_f));
     auto* b = Override("b", ty.f32(), Expr(1_f));
@@ -77,33 +77,33 @@
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 
     // Verify that constant id allocation order is deterministic.
-    ExpectConstantId(a, 0u);
-    ExpectConstantId(b, 3u);
-    ExpectConstantId(c, 2u);
-    ExpectConstantId(d, 4u);
-    ExpectConstantId(e, 5u);
-    ExpectConstantId(f, 1u);
+    ExpectOverrideId(a, 0u);
+    ExpectOverrideId(b, 3u);
+    ExpectOverrideId(c, 2u);
+    ExpectOverrideId(d, 4u);
+    ExpectOverrideId(e, 5u);
+    ExpectOverrideId(f, 1u);
 }
 
-TEST_F(ResolverPipelineOverridableConstantTest, DuplicateIds) {
+TEST_F(ResolverOverrideTest, DuplicateIds) {
     Override("a", ty.f32(), Expr(1_f), {Id(Source{{12, 34}}, 7u)});
     Override("b", ty.f32(), Expr(1_f), {Id(Source{{56, 78}}, 7u)});
 
     EXPECT_FALSE(r()->Resolve());
 
-    EXPECT_EQ(r()->error(), R"(56:78 error: pipeline constant IDs must be unique
-12:34 note: a pipeline constant with an ID of 7 was previously declared here:)");
+    EXPECT_EQ(r()->error(), R"(56:78 error: override IDs must be unique
+12:34 note: a override with an ID of 7 was previously declared here:)");
 }
 
-TEST_F(ResolverPipelineOverridableConstantTest, IdTooLarge) {
+TEST_F(ResolverOverrideTest, IdTooLarge) {
     Override("a", ty.f32(), Expr(1_f), {Id(Source{{12, 34}}, 65536u)});
 
     EXPECT_FALSE(r()->Resolve());
 
-    EXPECT_EQ(r()->error(), "12:34 error: pipeline constant IDs must be between 0 and 65535");
+    EXPECT_EQ(r()->error(), "12:34 error: override IDs must be between 0 and 65535");
 }
 
-TEST_F(ResolverPipelineOverridableConstantTest, F16_TemporallyBan) {
+TEST_F(ResolverOverrideTest, F16_TemporallyBan) {
     Enable(ast::Extension::kF16);
 
     Override(Source{{12, 34}}, "a", ty.f16(), Expr(1_h), {Id(1u)});
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index b7b7586..d861acf 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -149,7 +149,9 @@
         }
     }
 
-    AllocateOverridableConstantIds();
+    if (!AllocateOverridableConstantIds()) {
+        return false;
+    }
 
     SetShadows();
 
@@ -432,7 +434,7 @@
         /* constant_value */ nullptr, sem::BindingPoint{});
 
     if (auto* id = ast::GetAttribute<ast::IdAttribute>(v->attributes)) {
-        sem->SetConstantId(static_cast<uint16_t>(id->value));
+        sem->SetOverrideId(OverrideId{static_cast<decltype(OverrideId::value)>(id->value)});
     }
 
     sem->SetConstructor(rhs);
@@ -641,9 +643,19 @@
     return ast::Access::kReadWrite;
 }
 
-void Resolver::AllocateOverridableConstantIds() {
+bool Resolver::AllocateOverridableConstantIds() {
+    constexpr size_t kLimit = std::numeric_limits<decltype(OverrideId::value)>::max();
     // The next pipeline constant ID to try to allocate.
-    uint16_t next_constant_id = 0;
+    OverrideId next_id;
+    bool ids_exhausted = false;
+
+    auto increment_next_id = [&] {
+        if (next_id.value == kLimit) {
+            ids_exhausted = true;
+        } else {
+            next_id.value = next_id.value + 1;
+        }
+    };
 
     // Allocate constant IDs in global declaration order, so that they are
     // deterministic.
@@ -655,26 +667,28 @@
             continue;
         }
 
-        uint16_t constant_id;
+        OverrideId id;
         if (auto* id_attr = ast::GetAttribute<ast::IdAttribute>(override->attributes)) {
-            constant_id = static_cast<uint16_t>(id_attr->value);
+            id = OverrideId{static_cast<decltype(OverrideId::value)>(id_attr->value)};
         } else {
             // No ID was specified, so allocate the next available ID.
-            constant_id = next_constant_id;
-            while (constant_ids_.count(constant_id)) {
-                if (constant_id == UINT16_MAX) {
-                    TINT_ICE(Resolver, builder_->Diagnostics())
-                        << "no more pipeline constant IDs available";
-                    return;
-                }
-                constant_id++;
+            while (!ids_exhausted && override_ids_.count(next_id)) {
+                increment_next_id();
             }
-            next_constant_id = constant_id + 1;
+            if (ids_exhausted) {
+                AddError(
+                    "number of 'override' variables exceeded limit of " + std::to_string(kLimit),
+                    decl->source);
+                return false;
+            }
+            id = next_id;
+            increment_next_id();
         }
 
         auto* sem = sem_.Get<sem::GlobalVariable>(override);
-        const_cast<sem::GlobalVariable*>(sem)->SetConstantId(constant_id);
+        const_cast<sem::GlobalVariable*>(sem)->SetOverrideId(id);
     }
+    return true;
 }
 
 void Resolver::SetShadows() {
@@ -697,7 +711,8 @@
 
         if (auto* id_attr = attr->As<ast::IdAttribute>()) {
             // Track the constant IDs that are specified in the shader.
-            constant_ids_.emplace(id_attr->value, sem);
+            override_ids_.emplace(
+                OverrideId{static_cast<decltype(OverrideId::value)>(id_attr->value)}, sem);
         }
     }
 
@@ -705,7 +720,7 @@
         return nullptr;
     }
 
-    if (!validator_.GlobalVariable(sem, constant_ids_, atomic_composite_info_)) {
+    if (!validator_.GlobalVariable(sem, override_ids_, atomic_composite_info_)) {
         return nullptr;
     }
 
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index 03f1b9e..ccfaf6c 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -362,7 +362,8 @@
     ast::Access DefaultAccessForStorageClass(ast::StorageClass storage_class);
 
     /// Allocate constant IDs for pipeline-overridable constants.
-    void AllocateOverridableConstantIds();
+    /// @returns true on success, false on error
+    bool AllocateOverridableConstantIds();
 
     /// Set the shadowing information on variable declarations.
     /// @note this method must only be called after all semantic nodes are built.
@@ -422,7 +423,7 @@
     std::vector<sem::Function*> entry_points_;
     std::unordered_map<const sem::Type*, const Source&> atomic_composite_info_;
     utils::Bitset<0> marked_;
-    std::unordered_map<uint32_t, const sem::Variable*> constant_ids_;
+    std::unordered_map<OverrideId, const sem::Variable*> override_ids_;
     std::unordered_map<ArrayConstructorSig, sem::CallTarget*> array_ctors_;
     std::unordered_map<StructConstructorSig, sem::CallTarget*> struct_ctors_;
 
diff --git a/src/tint/resolver/struct_pipeline_stage_use_test.cc b/src/tint/resolver/struct_pipeline_stage_use_test.cc
index 1ca80df..58c7cae 100644
--- a/src/tint/resolver/struct_pipeline_stage_use_test.cc
+++ b/src/tint/resolver/struct_pipeline_stage_use_test.cc
@@ -66,7 +66,7 @@
     auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
 
     Func("main", {Param("param", ty.Of(s))}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
-         {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::Builtin::kPosition)});
+         {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::BuiltinValue::kPosition)});
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
@@ -77,7 +77,8 @@
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
-    auto* s = Structure("S", {Member("a", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+    auto* s =
+        Structure("S", {Member("a", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)})});
 
     Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))}, {Stage(ast::PipelineStage::kVertex)});
 
@@ -118,8 +119,8 @@
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
-    auto* s =
-        Structure("S", {Member("a", ty.u32(), {Builtin(ast::Builtin::kLocalInvocationIndex)})});
+    auto* s = Structure(
+        "S", {Member("a", ty.u32(), {Builtin(ast::BuiltinValue::kLocalInvocationIndex)})});
 
     Func("main", {Param("param", ty.Of(s))}, ty.void_(), {},
          {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
@@ -133,7 +134,8 @@
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
-    auto* s = Structure("S", {Member("a", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+    auto* s =
+        Structure("S", {Member("a", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)})});
 
     Func("vert_main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
          {Stage(ast::PipelineStage::kVertex)});
diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc
index 57bf6b0..905fc0e 100644
--- a/src/tint/resolver/uniformity.cc
+++ b/src/tint/resolver/uniformity.cc
@@ -973,8 +973,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::Builtin::kNumWorkgroups ||
-                    builtin->builtin == ast::Builtin::kWorkgroupId) {
+                if (builtin->builtin == ast::BuiltinValue::kNumWorkgroups ||
+                    builtin->builtin == ast::BuiltinValue::kWorkgroupId) {
                     return false;
                 }
             }
diff --git a/src/tint/resolver/validation_test.cc b/src/tint/resolver/validation_test.cc
index 24f420b..45c6d87 100644
--- a/src/tint/resolver/validation_test.cc
+++ b/src/tint/resolver/validation_test.cc
@@ -74,7 +74,7 @@
              Stage(ast::PipelineStage::kVertex),
          },
          {
-             Builtin(ast::Builtin::kPosition),
+             Builtin(ast::BuiltinValue::kPosition),
          });
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index 834d275..940e154 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -562,7 +562,7 @@
 
 bool Validator::GlobalVariable(
     const sem::GlobalVariable* global,
-    const std::unordered_map<uint32_t, const sem::Variable*>& constant_ids,
+    const std::unordered_map<OverrideId, const sem::Variable*>& override_ids,
     const std::unordered_map<const sem::Type*, const Source&>& atomic_composite_info) const {
     auto* decl = global->Declaration();
     bool ok = Switch(
@@ -627,7 +627,7 @@
 
             return Var(global);
         },
-        [&](const ast::Override*) { return Override(global, constant_ids); },
+        [&](const ast::Override*) { return Override(global, override_ids); },
         [&](const ast::Const*) {
             if (!decl->attributes.empty()) {
                 AddError("attribute is not valid for module-scope 'const' declaration",
@@ -763,7 +763,7 @@
 
 bool Validator::Override(
     const sem::Variable* v,
-    const std::unordered_map<uint32_t, const sem::Variable*>& constant_ids) const {
+    const std::unordered_map<OverrideId, const sem::Variable*>& override_ids) const {
     auto* decl = v->Declaration();
     auto* storage_ty = v->Type()->UnwrapRef();
 
@@ -776,19 +776,23 @@
     for (auto* attr : decl->attributes) {
         if (auto* id_attr = attr->As<ast::IdAttribute>()) {
             uint32_t id = id_attr->value;
-            auto it = constant_ids.find(id);
-            if (it != constant_ids.end() && it->second != v) {
-                AddError("pipeline constant IDs must be unique", attr->source);
-                AddNote("a pipeline constant with an ID of " + std::to_string(id) +
+            if (id > std::numeric_limits<decltype(OverrideId::value)>::max()) {
+                AddError(
+                    "override IDs must be between 0 and " +
+                        std::to_string(std::numeric_limits<decltype(OverrideId::value)>::max()),
+                    attr->source);
+                return false;
+            }
+            if (auto it =
+                    override_ids.find(OverrideId{static_cast<decltype(OverrideId::value)>(id)});
+                it != override_ids.end() && it->second != v) {
+                AddError("override IDs must be unique", attr->source);
+                AddNote("a override with an ID of " + std::to_string(id) +
                             " was previously declared here:",
                         ast::GetAttribute<ast::IdAttribute>(it->second->Declaration()->attributes)
                             ->source);
                 return false;
             }
-            if (id > 65535) {
-                AddError("pipeline constant IDs must be between 0 and 65535", attr->source);
-                return false;
-            }
         } else {
             AddError("attribute is not valid for 'override' declaration", attr->source);
             return false;
@@ -886,7 +890,7 @@
     bool is_stage_mismatch = false;
     bool is_output = !is_input;
     switch (attr->builtin) {
-        case ast::Builtin::kPosition:
+        case ast::BuiltinValue::kPosition:
             if (stage != ast::PipelineStage::kNone &&
                 !((is_input && stage == ast::PipelineStage::kFragment) ||
                   (is_output && stage == ast::PipelineStage::kVertex))) {
@@ -898,10 +902,10 @@
                 return false;
             }
             break;
-        case ast::Builtin::kGlobalInvocationId:
-        case ast::Builtin::kLocalInvocationId:
-        case ast::Builtin::kNumWorkgroups:
-        case ast::Builtin::kWorkgroupId:
+        case ast::BuiltinValue::kGlobalInvocationId:
+        case ast::BuiltinValue::kLocalInvocationId:
+        case ast::BuiltinValue::kNumWorkgroups:
+        case ast::BuiltinValue::kWorkgroupId:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kCompute && is_input)) {
                 is_stage_mismatch = true;
@@ -912,7 +916,7 @@
                 return false;
             }
             break;
-        case ast::Builtin::kFragDepth:
+        case ast::BuiltinValue::kFragDepth:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kFragment && !is_input)) {
                 is_stage_mismatch = true;
@@ -922,7 +926,7 @@
                 return false;
             }
             break;
-        case ast::Builtin::kFrontFacing:
+        case ast::BuiltinValue::kFrontFacing:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kFragment && is_input)) {
                 is_stage_mismatch = true;
@@ -932,7 +936,7 @@
                 return false;
             }
             break;
-        case ast::Builtin::kLocalInvocationIndex:
+        case ast::BuiltinValue::kLocalInvocationIndex:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kCompute && is_input)) {
                 is_stage_mismatch = true;
@@ -942,8 +946,8 @@
                 return false;
             }
             break;
-        case ast::Builtin::kVertexIndex:
-        case ast::Builtin::kInstanceIndex:
+        case ast::BuiltinValue::kVertexIndex:
+        case ast::BuiltinValue::kInstanceIndex:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kVertex && is_input)) {
                 is_stage_mismatch = true;
@@ -953,7 +957,7 @@
                 return false;
             }
             break;
-        case ast::Builtin::kSampleMask:
+        case ast::BuiltinValue::kSampleMask:
             if (stage != ast::PipelineStage::kNone && !(stage == ast::PipelineStage::kFragment)) {
                 is_stage_mismatch = true;
             }
@@ -962,7 +966,7 @@
                 return false;
             }
             break;
-        case ast::Builtin::kSampleIndex:
+        case ast::BuiltinValue::kSampleIndex:
             if (stage != ast::PipelineStage::kNone &&
                 !(stage == ast::PipelineStage::kFragment && is_input)) {
                 is_stage_mismatch = true;
@@ -1102,7 +1106,7 @@
     // already been seen, in 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.
-    std::unordered_set<ast::Builtin> builtins;
+    std::unordered_set<ast::BuiltinValue> builtins;
     std::unordered_set<uint32_t> locations;
     enum class ParamOrRetType {
         kParameter,
@@ -1237,7 +1241,7 @@
                 bool has_position = false;
                 if (pipeline_io_attribute) {
                     if (auto* builtin = pipeline_io_attribute->As<ast::BuiltinAttribute>()) {
-                        has_position = (builtin->builtin == ast::Builtin::kPosition);
+                        has_position = (builtin->builtin == ast::BuiltinValue::kPosition);
                     }
                 }
                 if (!has_position) {
@@ -1298,13 +1302,13 @@
     }
 
     if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
-        builtins.count(ast::Builtin::kPosition) == 0) {
+        builtins.count(ast::BuiltinValue::kPosition) == 0) {
         // 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::Builtin::kPosition) {
+                if (builtin->builtin == ast::BuiltinValue::kPosition) {
                     found = true;
                     break;
                 }
@@ -1708,13 +1712,13 @@
     }
 
     const auto extension = builtin->RequiredExtension();
-    if (extension == ast::Extension::kNone) {
+    if (extension == ast::Extension::kInvalid) {
         return true;
     }
 
     if (!enabled_extensions.contains(extension)) {
         AddError("cannot call built-in function '" + std::string(builtin->str()) +
-                     "' without extension " + ast::str(extension),
+                     "' without extension " + utils::ToString(extension),
                  call->Declaration()->source);
         return false;
     }
@@ -2111,7 +2115,7 @@
                                       /* is_input */ false)) {
                     return false;
                 }
-                if (builtin->builtin == ast::Builtin::kPosition) {
+                if (builtin->builtin == ast::BuiltinValue::kPosition) {
                     has_position = true;
                 }
             } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
diff --git a/src/tint/resolver/validator.h b/src/tint/resolver/validator.h
index ed20af0..e9f9cea 100644
--- a/src/tint/resolver/validator.h
+++ b/src/tint/resolver/validator.h
@@ -234,12 +234,12 @@
 
     /// Validates a global variable
     /// @param var the global variable to validate
-    /// @param constant_ids the set of constant ids in the module
+    /// @param override_id the set of override ids in the module
     /// @param atomic_composite_info atomic composite info in the module
     /// @returns true on success, false otherwise
     bool GlobalVariable(
         const sem::GlobalVariable* var,
-        const std::unordered_map<uint32_t, const sem::Variable*>& constant_ids,
+        const std::unordered_map<OverrideId, const sem::Variable*>& override_id,
         const std::unordered_map<const sem::Type*, const Source&>& atomic_composite_info) const;
 
     /// Validates an if statement
@@ -371,10 +371,10 @@
 
     /// Validates a 'override' variable declaration
     /// @param v the variable to validate
-    /// @param constant_ids the set of constant ids in the module
+    /// @param override_id the set of override ids in the module
     /// @returns true on success, false otherwise.
     bool Override(const sem::Variable* v,
-                  const std::unordered_map<uint32_t, const sem::Variable*>& constant_ids) const;
+                  const std::unordered_map<OverrideId, const sem::Variable*>& override_id) const;
 
     /// Validates a 'const' variable declaration
     /// @param v the variable to validate
diff --git a/src/tint/resolver/variable_validation_test.cc b/src/tint/resolver/variable_validation_test.cc
index e13585f..08312fe 100644
--- a/src/tint/resolver/variable_validation_test.cc
+++ b/src/tint/resolver/variable_validation_test.cc
@@ -77,6 +77,37 @@
     EXPECT_EQ(r()->error(), "12:34 error: override declaration requires a type or initializer");
 }
 
+TEST_F(ResolverVariableValidationTest, OverrideExceedsIDLimit_LastUnreserved) {
+    // override o0 : i32;
+    // override o1 : i32;
+    // ...
+    // override bang : i32;
+    constexpr size_t kLimit = std::numeric_limits<decltype(OverrideId::value)>::max();
+    for (size_t i = 0; i <= kLimit; i++) {
+        Override("o" + std::to_string(i), ty.i32(), nullptr);
+    }
+    Override(Source{{12, 34}}, "bang", ty.i32(), nullptr);
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: number of 'override' variables exceeded limit of 65535");
+}
+
+TEST_F(ResolverVariableValidationTest, OverrideExceedsIDLimit_LastReserved) {
+    // override o0 : i32;
+    // override o1 : i32;
+    // ...
+    // @id(N) override oN : i32;
+    constexpr size_t kLimit = std::numeric_limits<decltype(OverrideId::value)>::max();
+    Override("reserved", ty.i32(), nullptr, {Id(kLimit)});
+    for (size_t i = 0; i < kLimit; i++) {
+        Override("o" + std::to_string(i), ty.i32(), nullptr);
+    }
+    Override(Source{{12, 34}}, "bang", ty.i32(), nullptr);
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: number of 'override' variables exceeded limit of 65535");
+}
+
 TEST_F(ResolverVariableValidationTest, VarTypeNotConstructible) {
     // var i : i32;
     // var p : pointer<function, i32> = &v;
diff --git a/src/tint/sem/builtin.cc b/src/tint/sem/builtin.cc
index ee5a02b..7d0c56e 100644
--- a/src/tint/sem/builtin.cc
+++ b/src/tint/sem/builtin.cc
@@ -164,9 +164,9 @@
 
 ast::Extension Builtin::RequiredExtension() const {
     if (IsDP4a()) {
-        return ast::Extension::kChromiumExperimentalDP4a;
+        return ast::Extension::kChromiumExperimentalDp4A;
     }
-    return ast::Extension::kNone;
+    return ast::Extension::kInvalid;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/builtin_type.cc.tmpl b/src/tint/sem/builtin_type.cc.tmpl
index cc1e682..5737d8d 100644
--- a/src/tint/sem/builtin_type.cc.tmpl
+++ b/src/tint/sem/builtin_type.cc.tmpl
@@ -2,6 +2,9 @@
 --------------------------------------------------------------------------------
 Template file for use with tools/src/cmd/gen to generate builtin_type.cc
 
+To update the generated file, run:
+    ./tools/run gen
+
 See:
 * tools/src/cmd/gen for structures used by this template
 * https://golang.org/pkg/text/template/ for documentation on the template syntax
diff --git a/src/tint/sem/builtin_type.h.tmpl b/src/tint/sem/builtin_type.h.tmpl
index 9202a3d..84ceffc 100644
--- a/src/tint/sem/builtin_type.h.tmpl
+++ b/src/tint/sem/builtin_type.h.tmpl
@@ -2,6 +2,9 @@
 --------------------------------------------------------------------------------
 Template file for use with tools/src/cmd/gen to generate builtin_type.h
 
+To update the generated file, run:
+    ./tools/run gen
+
 See:
 * tools/src/cmd/gen for structures used by this template
 * https://golang.org/pkg/text/template/ for documentation on the template syntax
diff --git a/src/tint/sem/parameter_usage.cc.tmpl b/src/tint/sem/parameter_usage.cc.tmpl
index 7bb8b2e..62cb42e 100644
--- a/src/tint/sem/parameter_usage.cc.tmpl
+++ b/src/tint/sem/parameter_usage.cc.tmpl
@@ -2,6 +2,9 @@
 --------------------------------------------------------------------------------
 Template file for use with tools/src/cmd/gen to generate parameter_usage.cc
 
+To update the generated file, run:
+    ./tools/run gen
+
 See:
 * tools/src/cmd/gen for structures used by this template
 * https://golang.org/pkg/text/template/ for documentation on the template syntax
diff --git a/src/tint/sem/parameter_usage.h.tmpl b/src/tint/sem/parameter_usage.h.tmpl
index 5aaa8b4..7c09805 100644
--- a/src/tint/sem/parameter_usage.h.tmpl
+++ b/src/tint/sem/parameter_usage.h.tmpl
@@ -2,6 +2,9 @@
 --------------------------------------------------------------------------------
 Template file for use with tools/src/cmd/gen to generate parameter_usage.h
 
+To update the generated file, run:
+    ./tools/run gen
+
 See:
 * tools/src/cmd/gen for structures used by this template
 * https://golang.org/pkg/text/template/ for documentation on the template syntax
diff --git a/src/tint/sem/storage_texture.cc b/src/tint/sem/storage_texture.cc
index d8393d7..5b743e9 100644
--- a/src/tint/sem/storage_texture.cc
+++ b/src/tint/sem/storage_texture.cc
@@ -75,7 +75,7 @@
             return type_mgr.Get<sem::F32>();
         }
 
-        case ast::TexelFormat::kNone:
+        case ast::TexelFormat::kInvalid:
             break;
     }
 
diff --git a/src/tint/sem/variable.h b/src/tint/sem/variable.h
index ecc536b..2bf6d23 100644
--- a/src/tint/sem/variable.h
+++ b/src/tint/sem/variable.h
@@ -18,6 +18,8 @@
 #include <utility>
 #include <vector>
 
+#include "tint/override_id.h"
+
 #include "src/tint/ast/access.h"
 #include "src/tint/ast/storage_class.h"
 #include "src/tint/sem/binding_point.h"
@@ -165,15 +167,15 @@
     sem::BindingPoint BindingPoint() const { return binding_point_; }
 
     /// @param id the constant identifier to assign to this variable
-    void SetConstantId(uint16_t id) { constant_id_ = id; }
+    void SetOverrideId(OverrideId id) { override_id_ = id; }
 
     /// @returns the pipeline constant ID associated with the variable
-    uint16_t ConstantId() const { return constant_id_; }
+    tint::OverrideId OverrideId() const { return override_id_; }
 
   private:
     const sem::BindingPoint binding_point_;
 
-    uint16_t constant_id_ = 0;
+    tint::OverrideId override_id_;
 };
 
 /// Parameter is a function parameter
diff --git a/src/tint/templates/enums.tmpl.inc b/src/tint/templates/enums.tmpl.inc
new file mode 100644
index 0000000..d05d763
--- /dev/null
+++ b/src/tint/templates/enums.tmpl.inc
@@ -0,0 +1,160 @@
+{{- /* ------------------------------------------------------------------ */ -}}
+{{-                         define "EnumCase"                                -}}
+{{- /* Prints the 'Enum::kEntry' name for the provided  sem.EnumEntry     */ -}}
+{{- /* argument.                                                          */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{PascalCase $.Enum.Name}}::k{{PascalCase $.Name}}
+{{- end -}}
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{-                         define "DeclareEnum"                             -}}
+{{- /* Declares the 'enum class' for the provided sem.Enum argument.      */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum    := PascalCase $.Name -}}
+enum class {{$enum}} {
+    kInvalid,
+{{-   range $entry := $.Entries }}
+    k{{PascalCase $entry.Name}},{{if $entry.IsInternal}}  // Tint-internal enum entry - not parsed{{end}}
+{{-   end }}
+};
+
+/// @param out the std::ostream to write to
+/// @param value the {{$enum}}
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, {{$enum}} value);
+
+/// Parse{{$enum}} parses a {{$enum}} from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or {{$enum}}::kInvalid if the string could not be parsed.
+{{$enum}} Parse{{$enum}}(std::string_view str);
+
+{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{-                          define "ParseEnum"                              -}}
+{{- /* Implements the 'ParseEnum' function for the provided sem.Enum      */ -}}
+{{- /* argument.                                                          */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum    := PascalCase $.Name -}}
+/// Parse{{$enum}} parses a {{$enum}} from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or {{$enum}}::kInvalid if the string could not be parsed.
+{{$enum}} Parse{{$enum}}(std::string_view str) {
+{{-   range $entry := $.PublicEntries }}
+    if (str == "{{$entry.Name}}") {
+        return {{template "EnumCase" $entry}};
+    }
+{{-   end }}
+    return {{$enum}}::kInvalid;
+}
+{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{-                         define "EnumOStream"                             -}}
+{{- /* Implements the std::ostream 'operator<<()' function to print the   */ -}}
+{{- /* provided sem.Enum.                                                 */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum    := PascalCase $.Name -}}
+std::ostream& operator<<(std::ostream& out, {{$enum}} value) {
+    switch (value) {
+        case {{$enum}}::kInvalid:
+            return out << "invalid";
+{{-   range $entry := $.Entries }}
+        case {{template "EnumCase" $entry}}:
+            return out << "{{$entry.Name}}";
+{{-   end }}
+    }
+    return out << "<unknown>";
+}
+{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{-                        define "TestParsePrintEnum"                       -}}
+{{- /* Implements unit tests for parsing and printing the provided        */ -}}
+{{- /* sem.Enum argument.                                                 */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum    := PascalCase $.Name -}}
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    {{$enum}} value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+{{-   range $entry := $.PublicEntries }}
+    {"{{$entry.Name}}", {{template "EnumCase" $entry}}},
+{{-   end }}
+};
+
+static constexpr Case kInvalidCases[] = {
+{{-   $exclude := $.NameSet -}}
+{{-   range $entry := $.PublicEntries }}
+    {"{{Scramble $entry.Name $exclude}}", {{$enum}}::kInvalid},
+    {"{{Scramble $entry.Name $exclude}}", {{$enum}}::kInvalid},
+    {"{{Scramble $entry.Name $exclude}}", {{$enum}}::kInvalid},
+{{-   end }}
+};
+
+using {{$enum}}ParseTest = testing::TestWithParam<Case>;
+
+TEST_P({{$enum}}ParseTest, Parse) {
+    const char* string = GetParam().string;
+    {{$enum}} expect = GetParam().value;
+    EXPECT_EQ(expect, Parse{{$enum}}(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, {{$enum}}ParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases, {{$enum}}ParseTest, testing::ValuesIn(kInvalidCases));
+
+using {{$enum}}PrintTest = testing::TestWithParam<Case>;
+
+TEST_P({{$enum}}PrintTest, Print) {
+    {{$enum}} value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, {{$enum}}PrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+{{- end -}}
+
+
+{{- /* ------------------------------------------------------------------ */ -}}
+{{-                     define "BenchmarkParseEnum"                          -}}
+{{- /* Implements a micro-benchmark for parsing the provided sem.Enum     */ -}}
+{{- /* argument.                                                          */ -}}
+{{- /* ------------------------------------------------------------------ */ -}}
+{{- $enum    := PascalCase $.Name -}}
+void {{$enum}}Parser(::benchmark::State& state) {
+    std::array kStrings{
+{{-   $exclude := $.NameSet -}}
+{{-   range $entry := $.PublicEntries }}
+        "{{Scramble $entry.Name $exclude}}",
+        "{{Scramble $entry.Name $exclude}}",
+        "{{Scramble $entry.Name $exclude}}",
+        "{{$entry.Name}}",
+        "{{Scramble $entry.Name $exclude}}",
+        "{{Scramble $entry.Name $exclude}}",
+        "{{Scramble $entry.Name $exclude}}",
+{{-   end }}
+    };
+    for (auto _ : state) {
+        for (auto& str : kStrings) {
+            auto result = Parse{{$enum}}(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK({{$enum}}Parser);
+{{- end -}}
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/transform/canonicalize_entry_point_io.cc
index 51977d9..acec84f 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/transform/canonicalize_entry_point_io.cc
@@ -71,7 +71,7 @@
 // Returns true if `attrs` contains a `sample_mask` builtin.
 bool HasSampleMask(const ast::AttributeList& attrs) {
     auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attrs);
-    return builtin && builtin->builtin == ast::Builtin::kSampleMask;
+    return builtin && builtin->builtin == ast::BuiltinValue::kSampleMask;
 }
 
 }  // namespace
@@ -191,7 +191,7 @@
             if (builtin) {
                 if (cfg.shader_style == ShaderStyle::kGlsl) {
                     value = FromGLSLBuiltin(builtin->builtin, value, ast_type);
-                } else if (builtin->builtin == ast::Builtin::kSampleMask) {
+                } else if (builtin->builtin == ast::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);
@@ -366,7 +366,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<sem::U32>(),
-                  {ctx.dst->Builtin(ast::Builtin::kSampleMask)},
+                  {ctx.dst->Builtin(ast::BuiltinValue::kSampleMask)},
                   ctx.dst->Expr(u32(cfg.fixed_sample_mask)));
     }
 
@@ -374,7 +374,7 @@
     void AddVertexPointSize() {
         // Create a new output value and assign it a literal 1.0 value.
         AddOutput("vertex_point_size", ctx.dst->create<sem::F32>(),
-                  {ctx.dst->Builtin(ast::Builtin::kPointSize)}, ctx.dst->Expr(1_f));
+                  {ctx.dst->Builtin(ast::BuiltinValue::kPointSize)}, ctx.dst->Expr(1_f));
     }
 
     /// Create an expression for gl_Position.[component]
@@ -606,11 +606,11 @@
     /// @param stage the current pipeline stage
     /// @param storage_class the storage class (input or output)
     /// @returns the gl_ string corresponding to that builtin
-    const char* GLSLBuiltinToString(ast::Builtin builtin,
+    const char* GLSLBuiltinToString(ast::BuiltinValue builtin,
                                     ast::PipelineStage stage,
                                     ast::StorageClass storage_class) {
         switch (builtin) {
-            case ast::Builtin::kPosition:
+            case ast::BuiltinValue::kPosition:
                 switch (stage) {
                     case ast::PipelineStage::kVertex:
                         return "gl_Position";
@@ -619,27 +619,27 @@
                     default:
                         return "";
                 }
-            case ast::Builtin::kVertexIndex:
+            case ast::BuiltinValue::kVertexIndex:
                 return "gl_VertexID";
-            case ast::Builtin::kInstanceIndex:
+            case ast::BuiltinValue::kInstanceIndex:
                 return "gl_InstanceID";
-            case ast::Builtin::kFrontFacing:
+            case ast::BuiltinValue::kFrontFacing:
                 return "gl_FrontFacing";
-            case ast::Builtin::kFragDepth:
+            case ast::BuiltinValue::kFragDepth:
                 return "gl_FragDepth";
-            case ast::Builtin::kLocalInvocationId:
+            case ast::BuiltinValue::kLocalInvocationId:
                 return "gl_LocalInvocationID";
-            case ast::Builtin::kLocalInvocationIndex:
+            case ast::BuiltinValue::kLocalInvocationIndex:
                 return "gl_LocalInvocationIndex";
-            case ast::Builtin::kGlobalInvocationId:
+            case ast::BuiltinValue::kGlobalInvocationId:
                 return "gl_GlobalInvocationID";
-            case ast::Builtin::kNumWorkgroups:
+            case ast::BuiltinValue::kNumWorkgroups:
                 return "gl_NumWorkGroups";
-            case ast::Builtin::kWorkgroupId:
+            case ast::BuiltinValue::kWorkgroupId:
                 return "gl_WorkGroupID";
-            case ast::Builtin::kSampleIndex:
+            case ast::BuiltinValue::kSampleIndex:
                 return "gl_SampleID";
-            case ast::Builtin::kSampleMask:
+            case ast::BuiltinValue::kSampleMask:
                 if (storage_class == ast::StorageClass::kIn) {
                     return "gl_SampleMaskIn";
                 } else {
@@ -656,18 +656,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::Builtin builtin,
+    const ast::Expression* FromGLSLBuiltin(ast::BuiltinValue builtin,
                                            const ast::Expression* value,
                                            const ast::Type*& ast_type) {
         switch (builtin) {
-            case ast::Builtin::kVertexIndex:
-            case ast::Builtin::kInstanceIndex:
-            case ast::Builtin::kSampleIndex:
+            case ast::BuiltinValue::kVertexIndex:
+            case ast::BuiltinValue::kInstanceIndex:
+            case ast::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::Builtin::kSampleMask:
+            case ast::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);
@@ -686,14 +686,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::Builtin builtin,
+    const ast::Expression* ToGLSLBuiltin(ast::BuiltinValue builtin,
                                          const ast::Expression* value,
                                          const sem::Type*& type) {
         switch (builtin) {
-            case ast::Builtin::kVertexIndex:
-            case ast::Builtin::kInstanceIndex:
-            case ast::Builtin::kSampleIndex:
-            case ast::Builtin::kSampleMask:
+            case ast::BuiltinValue::kVertexIndex:
+            case ast::BuiltinValue::kInstanceIndex:
+            case ast::BuiltinValue::kSampleIndex:
+            case ast::BuiltinValue::kSampleMask:
                 type = ctx.dst->create<sem::I32>();
                 value = ctx.dst->Bitcast(CreateASTTypeFor(ctx, type), value);
                 break;
diff --git a/src/tint/transform/canonicalize_entry_point_io_test.cc b/src/tint/transform/canonicalize_entry_point_io_test.cc
index c8af902..f2af213 100644
--- a/src/tint/transform/canonicalize_entry_point_io_test.cc
+++ b/src/tint/transform/canonicalize_entry_point_io_test.cc
@@ -3163,7 +3163,7 @@
     auto* expect = R"(
 @builtin(position) @internal(disable_validation__ignore_storage_class) var<out> value : vec4<f32>;
 
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
 
 fn vert_main_inner() -> vec4<f32> {
   return vec4<f32>();
@@ -3197,7 +3197,7 @@
 struct tint_symbol {
   @builtin(position)
   value : vec4<f32>,
-  @builtin(pointsize)
+  @builtin(point_size)
   vertex_point_size : f32,
 }
 
@@ -3238,7 +3238,7 @@
     auto* expect = R"(
 @builtin(position) @internal(disable_validation__ignore_storage_class) var<out> pos_1 : vec4<f32>;
 
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
 
 struct VertOut {
   pos : vec4<f32>,
@@ -3279,7 +3279,7 @@
     auto* expect = R"(
 @builtin(position) @internal(disable_validation__ignore_storage_class) var<out> pos_1 : vec4<f32>;
 
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
 
 fn vert_main_inner() -> VertOut {
   return VertOut();
@@ -3325,7 +3325,7 @@
 struct tint_symbol {
   @builtin(position)
   pos : vec4<f32>,
-  @builtin(pointsize)
+  @builtin(point_size)
   vertex_point_size : f32,
 }
 
@@ -3367,7 +3367,7 @@
 struct tint_symbol {
   @builtin(position)
   pos : vec4<f32>,
-  @builtin(pointsize)
+  @builtin(point_size)
   vertex_point_size : f32,
 }
 
@@ -3432,7 +3432,7 @@
 
 @builtin(position) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_1_1 : vec4<f32>;
 
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
 
 var<private> vertex_point_size : f32;
 
@@ -3510,7 +3510,7 @@
 
 @builtin(position) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_1_1 : vec4<f32>;
 
-@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
+@builtin(point_size) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
 
 fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
   let x = (collide.collide + collide_1.collide);
@@ -3601,7 +3601,7 @@
   vertex_point_size : vec4<f32>,
   @builtin(position)
   vertex_point_size_1 : vec4<f32>,
-  @builtin(pointsize)
+  @builtin(point_size)
   vertex_point_size_2 : f32,
 }
 
@@ -3664,7 +3664,7 @@
   vertex_point_size : vec4<f32>,
   @builtin(position)
   vertex_point_size_1 : vec4<f32>,
-  @builtin(pointsize)
+  @builtin(point_size)
   vertex_point_size_2 : f32,
 }
 
@@ -3753,7 +3753,7 @@
   vertex_point_size : vec4<f32>,
   @builtin(position)
   vertex_point_size_1 : vec4<f32>,
-  @builtin(pointsize)
+  @builtin(point_size)
   vertex_point_size_2 : f32,
 }
 
@@ -3816,7 +3816,7 @@
   vertex_point_size : vec4<f32>,
   @builtin(position)
   vertex_point_size_1 : vec4<f32>,
-  @builtin(pointsize)
+  @builtin(point_size)
   vertex_point_size_2 : f32,
 }
 
diff --git a/src/tint/transform/first_index_offset.cc b/src/tint/transform/first_index_offset.cc
index 01f9771..6af162d 100644
--- a/src/tint/transform/first_index_offset.cc
+++ b/src/tint/transform/first_index_offset.cc
@@ -79,13 +79,13 @@
         if (auto* var = node->As<ast::Variable>()) {
             for (auto* attr : var->attributes) {
                 if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
-                    ast::Builtin builtin = builtin_attr->builtin;
-                    if (builtin == ast::Builtin::kVertexIndex) {
+                    ast::BuiltinValue builtin = builtin_attr->builtin;
+                    if (builtin == ast::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::Builtin::kInstanceIndex) {
+                    if (builtin == ast::BuiltinValue::kInstanceIndex) {
                         auto* sem_var = ctx.src->Sem().Get(var);
                         builtin_vars.emplace(sem_var, kFirstInstanceName);
                         has_vertex_or_instance_index = true;
@@ -96,13 +96,13 @@
         if (auto* member = node->As<ast::StructMember>()) {
             for (auto* attr : member->attributes) {
                 if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
-                    ast::Builtin builtin = builtin_attr->builtin;
-                    if (builtin == ast::Builtin::kVertexIndex) {
+                    ast::BuiltinValue builtin = builtin_attr->builtin;
+                    if (builtin == ast::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::Builtin::kInstanceIndex) {
+                    if (builtin == ast::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/module_scope_var_to_entry_point_param.cc b/src/tint/transform/module_scope_var_to_entry_point_param.cc
index 5a7eecc..7bd3991 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/transform/module_scope_var_to_entry_point_param.cc
@@ -219,9 +219,10 @@
             case ast::StorageClass::kHandle:
             case ast::StorageClass::kWorkgroup:
                 break;
-            default:
+            default: {
                 TINT_ICE(Transform, ctx.dst->Diagnostics())
                     << "unhandled module-scope storage class (" << sc << ")";
+            }
         }
 
         // Use a pointer for non-handle types.
diff --git a/src/tint/transform/num_workgroups_from_uniform.cc b/src/tint/transform/num_workgroups_from_uniform.cc
index 6b93e73..86310a9 100644
--- a/src/tint/transform/num_workgroups_from_uniform.cc
+++ b/src/tint/transform/num_workgroups_from_uniform.cc
@@ -52,7 +52,7 @@
 bool NumWorkgroupsFromUniform::ShouldRun(const Program* program, const DataMap&) const {
     for (auto* node : program->ASTNodes().Objects()) {
         if (auto* attr = node->As<ast::BuiltinAttribute>()) {
-            if (attr->builtin == ast::Builtin::kNumWorkgroups) {
+            if (attr->builtin == ast::BuiltinValue::kNumWorkgroups) {
                 return true;
             }
         }
@@ -89,7 +89,7 @@
             for (auto* member : str->Members()) {
                 auto* builtin =
                     ast::GetAttribute<ast::BuiltinAttribute>(member->Declaration()->attributes);
-                if (!builtin || builtin->builtin != ast::Builtin::kNumWorkgroups) {
+                if (!builtin || builtin->builtin != ast::BuiltinValue::kNumWorkgroups) {
                     continue;
                 }
 
diff --git a/src/tint/transform/single_entry_point.cc b/src/tint/transform/single_entry_point.cc
index ab7bed3..133c836 100644
--- a/src/tint/transform/single_entry_point.cc
+++ b/src/tint/transform/single_entry_point.cc
@@ -76,11 +76,11 @@
             [&](const ast::Override* override) {
                 if (referenced_vars.count(override)) {
                     if (!ast::HasAttribute<ast::IdAttribute>(override->attributes)) {
-                        // If the constant doesn't already have an @id() attribute, add one
+                        // If the override doesn't already have an @id() attribute, add one
                         // so that its allocated ID so that it won't be affected by other
-                        // stripped away constants
+                        // stripped away overrides
                         auto* global = sem.Get(override);
-                        const auto* id = ctx.dst->Id(global->ConstantId());
+                        const auto* id = ctx.dst->Id(global->OverrideId());
                         ctx.InsertFront(override->attributes, id);
                     }
                     ctx.dst->AST().AddGlobalVariable(ctx.Clone(override));
diff --git a/src/tint/transform/vertex_pulling.cc b/src/tint/transform/vertex_pulling.cc
index 50b8f28..43531eb 100644
--- a/src/tint/transform/vertex_pulling.cc
+++ b/src/tint/transform/vertex_pulling.cc
@@ -709,11 +709,11 @@
             location_info[location->value] = info;
         } else if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
             // Check for existing vertex_index and instance_index builtins.
-            if (builtin->builtin == ast::Builtin::kVertexIndex) {
+            if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
                 vertex_index_expr = [this, param]() {
                     return ctx.dst->Expr(ctx.Clone(param->symbol));
                 };
-            } else if (builtin->builtin == ast::Builtin::kInstanceIndex) {
+            } else if (builtin->builtin == ast::BuiltinValue::kInstanceIndex) {
                 instance_index_expr = [this, param]() {
                     return ctx.dst->Expr(ctx.Clone(param->symbol));
                 };
@@ -756,9 +756,9 @@
             } else if (auto* builtin =
                            ast::GetAttribute<ast::BuiltinAttribute>(member->attributes)) {
                 // Check for existing vertex_index and instance_index builtins.
-                if (builtin->builtin == ast::Builtin::kVertexIndex) {
+                if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
                     vertex_index_expr = member_expr;
-                } else if (builtin->builtin == ast::Builtin::kInstanceIndex) {
+                } else if (builtin->builtin == ast::BuiltinValue::kInstanceIndex) {
                     instance_index_expr = member_expr;
                 }
                 members_to_clone.push_back(member);
@@ -825,8 +825,9 @@
             for (const VertexBufferLayoutDescriptor& layout : cfg.vertex_state) {
                 if (layout.step_mode == VertexStepMode::kVertex) {
                     auto name = ctx.dst->Symbols().New("tint_pulling_vertex_index");
-                    new_function_parameters.push_back(ctx.dst->Param(
-                        name, ctx.dst->ty.u32(), {ctx.dst->Builtin(ast::Builtin::kVertexIndex)}));
+                    new_function_parameters.push_back(
+                        ctx.dst->Param(name, ctx.dst->ty.u32(),
+                                       {ctx.dst->Builtin(ast::BuiltinValue::kVertexIndex)}));
                     vertex_index_expr = [this, name]() { return ctx.dst->Expr(name); };
                     break;
                 }
@@ -836,8 +837,9 @@
             for (const VertexBufferLayoutDescriptor& layout : cfg.vertex_state) {
                 if (layout.step_mode == VertexStepMode::kInstance) {
                     auto name = ctx.dst->Symbols().New("tint_pulling_instance_index");
-                    new_function_parameters.push_back(ctx.dst->Param(
-                        name, ctx.dst->ty.u32(), {ctx.dst->Builtin(ast::Builtin::kInstanceIndex)}));
+                    new_function_parameters.push_back(
+                        ctx.dst->Param(name, ctx.dst->ty.u32(),
+                                       {ctx.dst->Builtin(ast::BuiltinValue::kInstanceIndex)}));
                     instance_index_expr = [this, name]() { return ctx.dst->Expr(name); };
                     break;
                 }
diff --git a/src/tint/transform/zero_init_workgroup_memory.cc b/src/tint/transform/zero_init_workgroup_memory.cc
index 96395f1..890ecef 100644
--- a/src/tint/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/transform/zero_init_workgroup_memory.cc
@@ -137,7 +137,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::Builtin::kLocalInvocationIndex) {
+                if (builtin->builtin == ast::BuiltinValue::kLocalInvocationIndex) {
                     local_index = [=] { return b.Expr(ctx.Clone(param->symbol)); };
                     break;
                 }
@@ -147,7 +147,7 @@
                 for (auto* member : str->Members()) {
                     if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(
                             member->Declaration()->attributes)) {
-                        if (builtin->builtin == ast::Builtin::kLocalInvocationIndex) {
+                        if (builtin->builtin == ast::BuiltinValue::kLocalInvocationIndex) {
                             local_index = [=] {
                                 auto* param_expr = b.Expr(ctx.Clone(param->symbol));
                                 auto member_name = ctx.Clone(member->Declaration()->symbol);
@@ -162,7 +162,7 @@
         if (!local_index) {
             // No existing local index parameter. Append one to the entry point.
             auto* param = b.Param(b.Symbols().New("local_invocation_index"), b.ty.u32(),
-                                  {b.Builtin(ast::Builtin::kLocalInvocationIndex)});
+                                  {b.Builtin(ast::BuiltinValue::kLocalInvocationIndex)});
             ctx.InsertBack(fn->params, param);
             local_index = [=] { return b.Expr(param->symbol); };
         }
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 5473eaf..5cd0999 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -85,10 +85,10 @@
            op == tint::ast::BinaryOp::kGreaterThanEqual;
 }
 
-bool RequiresOESSampleVariables(tint::ast::Builtin builtin) {
+bool RequiresOESSampleVariables(tint::ast::BuiltinValue builtin) {
     switch (builtin) {
-        case tint::ast::Builtin::kSampleIndex:
-        case tint::ast::Builtin::kSampleMask:
+        case tint::ast::BuiltinValue::kSampleIndex:
+        case tint::ast::BuiltinValue::kSampleMask:
             return true;
         default:
             return false;
@@ -141,7 +141,7 @@
             return "rgba32i";
         case ast::TexelFormat::kRgba32Float:
             return "rgba32f";
-        case ast::TexelFormat::kNone:
+        case ast::TexelFormat::kInvalid:
             return "unknown";
     }
     return "unknown";
@@ -1932,10 +1932,11 @@
                 case ast::StorageClass::kIn:
                 case ast::StorageClass::kOut:
                     return EmitIOVariable(sem);
-                default:
+                default: {
                     TINT_ICE(Writer, diagnostics_)
                         << "unhandled storage class " << sem->StorageClass();
                     return false;
+                }
             }
         },
         [&](const ast::Let* let) { return EmitProgramConstVariable(let); },
@@ -2158,7 +2159,7 @@
                     TINT_ICE(Writer, builder_.Diagnostics())
                         << "expected a pipeline-overridable constant";
                 }
-                out << kSpecConstantPrefix << global->ConstantId();
+                out << kSpecConstantPrefix << global->OverrideId().value;
             } else {
                 out << std::to_string(wgsize[i].value);
             }
@@ -3052,18 +3053,18 @@
     auto* type = sem->Type();
 
     auto* global = sem->As<sem::GlobalVariable>();
-    auto const_id = global->ConstantId();
+    auto override_id = global->OverrideId();
 
-    line() << "#ifndef " << kSpecConstantPrefix << const_id;
+    line() << "#ifndef " << kSpecConstantPrefix << override_id.value;
 
     if (override->constructor != nullptr) {
         auto out = line();
-        out << "#define " << kSpecConstantPrefix << const_id << " ";
+        out << "#define " << kSpecConstantPrefix << override_id.value << " ";
         if (!EmitExpression(out, override->constructor)) {
             return false;
         }
     } else {
-        line() << "#error spec constant required for constant id " << const_id;
+        line() << "#error spec constant required for constant id " << override_id.value;
     }
     line() << "#endif";
     {
@@ -3073,7 +3074,7 @@
                              builder_.Symbols().NameFor(override->symbol))) {
             return false;
         }
-        out << " = " << kSpecConstantPrefix << const_id << ";";
+        out << " = " << kSpecConstantPrefix << override_id.value << ";";
     }
 
     return true;
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index 811dd91..86be974 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -465,11 +465,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::Builtin builtin, ast::PipelineStage stage);
+    const char* builtin_to_string(ast::BuiltinValue builtin, ast::PipelineStage stage);
     /// Converts a builtin to a sem::Type appropriate for GLSL.
     /// @param builtin the builtin to convert
     /// @returns the appropriate semantic type or null on error.
-    sem::Type* builtin_type(ast::Builtin builtin);
+    sem::Type* builtin_type(ast::BuiltinValue builtin);
 
   private:
     enum class VarType { kIn, kOut };
diff --git a/src/tint/writer/glsl/generator_impl_function_test.cc b/src/tint/writer/glsl/generator_impl_function_test.cc
index 450041b..d1f7a5e 100644
--- a/src/tint/writer/glsl/generator_impl_function_test.cc
+++ b/src/tint/writer/glsl/generator_impl_function_test.cc
@@ -165,7 +165,7 @@
     // fn frag_main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
     //   return coord.x;
     // }
-    auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
+    auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)});
     Func("frag_main",
          {
              coord_in,
@@ -178,7 +178,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          {
-             Builtin(ast::Builtin::kFragDepth),
+             Builtin(ast::BuiltinValue::kFragDepth),
          });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -215,7 +215,7 @@
     // }
     auto* interface_struct = Structure(
         "Interface", {
-                         Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                         Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)}),
                          Member("col1", ty.f32(), {Location(1)}),
                          Member("col2", ty.f32(), {Location(2)}),
                      });
@@ -295,7 +295,7 @@
   // }
   auto* vertex_output_struct = Structure(
       "VertexOutput",
-      {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+      {Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)})});
 
   Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
        {Return(Construct(ty.Of(vertex_output_struct),
diff --git a/src/tint/writer/glsl/generator_impl_test.cc b/src/tint/writer/glsl/generator_impl_test.cc
index abae4c9..f45d0d0 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(),
               ast::AttributeList{
-                  Builtin(ast::Builtin::kSampleIndex),
+                  Builtin(ast::BuiltinValue::kSampleIndex),
                   Disable(ast::DisabledValidation::kIgnoreStorageClass),
               },
               ast::StorageClass::kIn);
@@ -84,7 +84,7 @@
 TEST_F(GlslGeneratorImplTest, GenerateSampleIndexDesktop) {
     GlobalVar("gl_SampleID", ty.i32(),
               ast::AttributeList{
-                  Builtin(ast::Builtin::kSampleIndex),
+                  Builtin(ast::BuiltinValue::kSampleIndex),
                   Disable(ast::DisabledValidation::kIgnoreStorageClass),
               },
               ast::StorageClass::kIn);
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index a9fddc3..d106804 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -2849,10 +2849,11 @@
                     return EmitPrivateVariable(sem);
                 case ast::StorageClass::kWorkgroup:
                     return EmitWorkgroupVariable(sem);
-                default:
+                default: {
                     TINT_ICE(Writer, diagnostics_)
                         << "unhandled storage class " << sem->StorageClass();
                     return false;
+                }
             }
         },
         [&](const ast::Override* override) { return EmitOverride(override); },
@@ -2981,29 +2982,29 @@
     return true;
 }
 
-std::string GeneratorImpl::builtin_to_attribute(ast::Builtin builtin) const {
+std::string GeneratorImpl::builtin_to_attribute(ast::BuiltinValue builtin) const {
     switch (builtin) {
-        case ast::Builtin::kPosition:
+        case ast::BuiltinValue::kPosition:
             return "SV_Position";
-        case ast::Builtin::kVertexIndex:
+        case ast::BuiltinValue::kVertexIndex:
             return "SV_VertexID";
-        case ast::Builtin::kInstanceIndex:
+        case ast::BuiltinValue::kInstanceIndex:
             return "SV_InstanceID";
-        case ast::Builtin::kFrontFacing:
+        case ast::BuiltinValue::kFrontFacing:
             return "SV_IsFrontFace";
-        case ast::Builtin::kFragDepth:
+        case ast::BuiltinValue::kFragDepth:
             return "SV_Depth";
-        case ast::Builtin::kLocalInvocationId:
+        case ast::BuiltinValue::kLocalInvocationId:
             return "SV_GroupThreadID";
-        case ast::Builtin::kLocalInvocationIndex:
+        case ast::BuiltinValue::kLocalInvocationIndex:
             return "SV_GroupIndex";
-        case ast::Builtin::kGlobalInvocationId:
+        case ast::BuiltinValue::kGlobalInvocationId:
             return "SV_DispatchThreadID";
-        case ast::Builtin::kWorkgroupId:
+        case ast::BuiltinValue::kWorkgroupId:
             return "SV_GroupID";
-        case ast::Builtin::kSampleIndex:
+        case ast::BuiltinValue::kSampleIndex:
             return "SV_SampleIndex";
-        case ast::Builtin::kSampleMask:
+        case ast::BuiltinValue::kSampleMask:
             return "SV_Coverage";
         default:
             break;
@@ -3060,7 +3061,7 @@
                         TINT_ICE(Writer, diagnostics_)
                             << "expected a pipeline-overridable constant";
                     }
-                    out << kSpecConstantPrefix << global->ConstantId();
+                    out << kSpecConstantPrefix << global->OverrideId().value;
                 } else {
                     out << std::to_string(wgsize[i].value);
                 }
@@ -4100,18 +4101,18 @@
     auto* sem = builder_.Sem().Get(override);
     auto* type = sem->Type();
 
-    auto const_id = sem->ConstantId();
+    auto override_id = sem->OverrideId();
 
-    line() << "#ifndef " << kSpecConstantPrefix << const_id;
+    line() << "#ifndef " << kSpecConstantPrefix << override_id.value;
 
     if (override->constructor != nullptr) {
         auto out = line();
-        out << "#define " << kSpecConstantPrefix << const_id << " ";
+        out << "#define " << kSpecConstantPrefix << override_id.value << " ";
         if (!EmitExpression(out, override->constructor)) {
             return false;
         }
     } else {
-        line() << "#error spec constant required for constant id " << const_id;
+        line() << "#error spec constant required for constant id " << override_id.value;
     }
     line() << "#endif";
     {
@@ -4121,7 +4122,7 @@
                              builder_.Symbols().NameFor(override->symbol))) {
             return false;
         }
-        out << " = " << kSpecConstantPrefix << const_id << ";";
+        out << " = " << kSpecConstantPrefix << override_id.value << ";";
     }
     return true;
 }
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index 74ce70c..a282451 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -489,7 +489,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::Builtin builtin) const;
+    std::string builtin_to_attribute(ast::BuiltinValue builtin) const;
 
     /// Converts interpolation attributes to a HLSL modifiers
     /// @param type the interpolation type
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index d008ab8..008ea6c 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -725,7 +725,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Dot4I8Packed) {
-    Enable(ast::Extension::kChromiumExperimentalDP4a);
+    Enable(ast::Extension::kChromiumExperimentalDp4A);
 
     auto* val1 = Var("val1", ty.u32());
     auto* val2 = Var("val2", ty.u32());
@@ -751,7 +751,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Dot4U8Packed) {
-    Enable(ast::Extension::kChromiumExperimentalDP4a);
+    Enable(ast::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 89d74c5..9314fb8 100644
--- a/src/tint/writer/hlsl/generator_impl_function_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_function_test.cc
@@ -156,7 +156,7 @@
     // fn frag_main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
     //   return coord.x;
     // }
-    auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
+    auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)});
     Func("frag_main", {coord_in}, ty.f32(),
          {
              Return(MemberAccessor("coord", "x")),
@@ -165,7 +165,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          {
-             Builtin(ast::Builtin::kFragDepth),
+             Builtin(ast::BuiltinValue::kFragDepth),
          });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -207,7 +207,7 @@
     // }
     auto* interface_struct = Structure(
         "Interface", {
-                         Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                         Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)}),
                          Member("col1", ty.f32(), {Location(1)}),
                          Member("col2", ty.f32(), {Location(2)}),
                      });
@@ -287,7 +287,7 @@
     //   return foo(0.25);
     // }
     auto* vertex_output_struct = Structure(
-        "VertexOutput", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+        "VertexOutput", {Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)})});
 
     Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
          {Return(Construct(ty.Of(vertex_output_struct),
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 d5dee6f..9dc9acb 100644
--- a/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
@@ -244,10 +244,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override) {
-    auto* var = Override("pos", ty.f32(), Expr(3_f),
-                         ast::AttributeList{
-                             Id(23),
-                         });
+    auto* var = Override("pos", ty.f32(), Expr(3_f), {Id(23)});
 
     GeneratorImpl& gen = Build();
 
@@ -260,10 +257,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override_NoConstructor) {
-    auto* var = Override("pos", ty.f32(), nullptr,
-                         ast::AttributeList{
-                             Id(23),
-                         });
+    auto* var = Override("pos", ty.f32(), nullptr, {Id(23)});
 
     GeneratorImpl& gen = Build();
 
@@ -276,10 +270,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override_NoId) {
-    auto* a = Override("a", ty.f32(), Expr(3_f),
-                       ast::AttributeList{
-                           Id(0),
-                       });
+    auto* a = Override("a", ty.f32(), Expr(3_f), {Id(0)});
     auto* b = Override("b", ty.f32(), Expr(2_f));
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/hlsl/generator_impl_test.cc b/src/tint/writer/hlsl/generator_impl_test.cc
index 997f51a..35b9c82 100644
--- a/src/tint/writer/hlsl/generator_impl_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_test.cc
@@ -40,7 +40,7 @@
 }
 
 struct HlslBuiltinData {
-    ast::Builtin builtin;
+    ast::BuiltinValue builtin;
     const char* attribute_name;
 };
 inline std::ostream& operator<<(std::ostream& out, HlslBuiltinData data) {
@@ -57,17 +57,17 @@
 INSTANTIATE_TEST_SUITE_P(
     HlslGeneratorImplTest,
     HlslBuiltinConversionTest,
-    testing::Values(HlslBuiltinData{ast::Builtin::kPosition, "SV_Position"},
-                    HlslBuiltinData{ast::Builtin::kVertexIndex, "SV_VertexID"},
-                    HlslBuiltinData{ast::Builtin::kInstanceIndex, "SV_InstanceID"},
-                    HlslBuiltinData{ast::Builtin::kFrontFacing, "SV_IsFrontFace"},
-                    HlslBuiltinData{ast::Builtin::kFragDepth, "SV_Depth"},
-                    HlslBuiltinData{ast::Builtin::kLocalInvocationId, "SV_GroupThreadID"},
-                    HlslBuiltinData{ast::Builtin::kLocalInvocationIndex, "SV_GroupIndex"},
-                    HlslBuiltinData{ast::Builtin::kGlobalInvocationId, "SV_DispatchThreadID"},
-                    HlslBuiltinData{ast::Builtin::kWorkgroupId, "SV_GroupID"},
-                    HlslBuiltinData{ast::Builtin::kSampleIndex, "SV_SampleIndex"},
-                    HlslBuiltinData{ast::Builtin::kSampleMask, "SV_Coverage"}));
+    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"}));
 
 }  // namespace
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 626a11d..3c1525f 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -1862,33 +1862,33 @@
     return true;
 }
 
-std::string GeneratorImpl::builtin_to_attribute(ast::Builtin builtin) const {
+std::string GeneratorImpl::builtin_to_attribute(ast::BuiltinValue builtin) const {
     switch (builtin) {
-        case ast::Builtin::kPosition:
+        case ast::BuiltinValue::kPosition:
             return "position";
-        case ast::Builtin::kVertexIndex:
+        case ast::BuiltinValue::kVertexIndex:
             return "vertex_id";
-        case ast::Builtin::kInstanceIndex:
+        case ast::BuiltinValue::kInstanceIndex:
             return "instance_id";
-        case ast::Builtin::kFrontFacing:
+        case ast::BuiltinValue::kFrontFacing:
             return "front_facing";
-        case ast::Builtin::kFragDepth:
+        case ast::BuiltinValue::kFragDepth:
             return "depth(any)";
-        case ast::Builtin::kLocalInvocationId:
+        case ast::BuiltinValue::kLocalInvocationId:
             return "thread_position_in_threadgroup";
-        case ast::Builtin::kLocalInvocationIndex:
+        case ast::BuiltinValue::kLocalInvocationIndex:
             return "thread_index_in_threadgroup";
-        case ast::Builtin::kGlobalInvocationId:
+        case ast::BuiltinValue::kGlobalInvocationId:
             return "thread_position_in_grid";
-        case ast::Builtin::kWorkgroupId:
+        case ast::BuiltinValue::kWorkgroupId:
             return "threadgroup_position_in_grid";
-        case ast::Builtin::kNumWorkgroups:
+        case ast::BuiltinValue::kNumWorkgroups:
             return "threadgroups_per_grid";
-        case ast::Builtin::kSampleIndex:
+        case ast::BuiltinValue::kSampleIndex:
             return "sample_id";
-        case ast::Builtin::kSampleMask:
+        case ast::BuiltinValue::kSampleMask:
             return "sample_mask";
-        case ast::Builtin::kPointSize:
+        case ast::BuiltinValue::kPointSize:
             return "point_size";
         default:
             break;
@@ -3063,7 +3063,7 @@
     }
     out << " " << program_->Symbols().NameFor(override->symbol);
 
-    out << " [[function_constant(" << global->ConstantId() << ")]];";
+    out << " [[function_constant(" << global->OverrideId().value << ")]];";
 
     return true;
 }
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index f27d258..137b365 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -374,7 +374,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::Builtin builtin) const;
+    std::string builtin_to_attribute(ast::BuiltinValue builtin) const;
 
     /// Converts interpolation attributes to an MSL attribute
     /// @param type the interpolation type
diff --git a/src/tint/writer/msl/generator_impl_function_test.cc b/src/tint/writer/msl/generator_impl_function_test.cc
index e520d7a..c3f926d 100644
--- a/src/tint/writer/msl/generator_impl_function_test.cc
+++ b/src/tint/writer/msl/generator_impl_function_test.cc
@@ -135,7 +135,7 @@
     // fn frag_main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
     //   return coord.x;
     // }
-    auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
+    auto* coord_in = Param("coord", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)});
     Func("frag_main", {coord_in}, ty.f32(),
          {
              Return(MemberAccessor("coord", "x")),
@@ -144,7 +144,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          {
-             Builtin(ast::Builtin::kFragDepth),
+             Builtin(ast::BuiltinValue::kFragDepth),
          });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -188,7 +188,7 @@
         "Interface", {
                          Member("col1", ty.f32(), {Location(1)}),
                          Member("col2", ty.f32(), {Location(2)}),
-                         Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                         Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)}),
                      });
 
     Func("vert_main", {}, ty.Of(interface_struct),
@@ -268,7 +268,7 @@
     //   return foo(0.25);
     // }
     auto* vertex_output_struct = Structure(
-        "VertexOutput", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+        "VertexOutput", {Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)})});
 
     Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
          {
diff --git a/src/tint/writer/msl/generator_impl_test.cc b/src/tint/writer/msl/generator_impl_test.cc
index aec9bfb..45010b2 100644
--- a/src/tint/writer/msl/generator_impl_test.cc
+++ b/src/tint/writer/msl/generator_impl_test.cc
@@ -52,7 +52,7 @@
 }
 
 struct MslBuiltinData {
-    ast::Builtin builtin;
+    ast::BuiltinValue builtin;
     const char* attribute_name;
 };
 inline std::ostream& operator<<(std::ostream& out, MslBuiltinData data) {
@@ -71,23 +71,23 @@
     MslGeneratorImplTest,
     MslBuiltinConversionTest,
     testing::Values(
-        MslBuiltinData{ast::Builtin::kPosition, "position"},
-        MslBuiltinData{ast::Builtin::kVertexIndex, "vertex_id"},
-        MslBuiltinData{ast::Builtin::kInstanceIndex, "instance_id"},
-        MslBuiltinData{ast::Builtin::kFrontFacing, "front_facing"},
-        MslBuiltinData{ast::Builtin::kFragDepth, "depth(any)"},
-        MslBuiltinData{ast::Builtin::kLocalInvocationId, "thread_position_in_threadgroup"},
-        MslBuiltinData{ast::Builtin::kLocalInvocationIndex, "thread_index_in_threadgroup"},
-        MslBuiltinData{ast::Builtin::kGlobalInvocationId, "thread_position_in_grid"},
-        MslBuiltinData{ast::Builtin::kWorkgroupId, "threadgroup_position_in_grid"},
-        MslBuiltinData{ast::Builtin::kNumWorkgroups, "threadgroups_per_grid"},
-        MslBuiltinData{ast::Builtin::kSampleIndex, "sample_id"},
-        MslBuiltinData{ast::Builtin::kSampleMask, "sample_mask"},
-        MslBuiltinData{ast::Builtin::kPointSize, "point_size"}));
+        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"}));
 
 TEST_F(MslGeneratorImplTest, HasInvariantAttribute_True) {
-    auto* out = Structure(
-        "Out", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition), Invariant()})});
+    auto* out = Structure("Out", {Member("pos", ty.vec4<f32>(),
+                                         {Builtin(ast::BuiltinValue::kPosition), Invariant()})});
     Func("vert_main", {}, ty.Of(out), {Return(Construct(ty.Of(out)))},
          {Stage(ast::PipelineStage::kVertex)});
 
@@ -118,7 +118,7 @@
 
 TEST_F(MslGeneratorImplTest, HasInvariantAttribute_False) {
     auto* out =
-        Structure("Out", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+        Structure("Out", {Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)})});
     Func("vert_main", {}, ty.Of(out), {Return(Construct(ty.Of(out)))},
          {Stage(ast::PipelineStage::kVertex)});
 
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 4737b54..488cbf8 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -380,7 +380,7 @@
 
 bool Builder::GenerateExtension(ast::Extension extension) {
     switch (extension) {
-        case ast::Extension::kChromiumExperimentalDP4a:
+        case ast::Extension::kChromiumExperimentalDp4A:
             push_extension("SPV_KHR_integer_dot_product");
             push_capability(SpvCapabilityDotProductKHR);
             push_capability(SpvCapabilityDotProductInput4x8BitPackedKHR);
@@ -540,7 +540,7 @@
                             << "expected a pipeline-overridable constant";
                     }
                     constant.is_spec_op = true;
-                    constant.constant_id = sem_const->ConstantId();
+                    constant.constant_id = sem_const->OverrideId().value;
                 }
 
                 auto result = GenerateConstantIfNeeded(constant);
@@ -563,7 +563,7 @@
     }
 
     for (auto builtin : func_sem->TransitivelyReferencedBuiltinVariables()) {
-        if (builtin.second->builtin == ast::Builtin::kFragDepth) {
+        if (builtin.second->builtin == ast::BuiltinValue::kFragDepth) {
             push_execution_mode(spv::Op::OpExecutionMode,
                                 {Operand(id), U32Operand(SpvExecutionModeDepthReplacing)});
         }
@@ -1340,7 +1340,7 @@
     // Generate the zero initializer if there are no values provided.
     if (args.IsEmpty()) {
         if (global_var && global_var->Declaration()->Is<ast::Override>()) {
-            auto constant_id = global_var->ConstantId();
+            auto constant_id = global_var->OverrideId().value;
             if (result_type->Is<sem::I32>()) {
                 return GenerateConstantIfNeeded(ScalarConstant::I32(0).AsSpecOp(constant_id));
             }
@@ -1664,7 +1664,7 @@
     auto* global = builder_.Sem().Get<sem::GlobalVariable>(var);
     if (global && global->Declaration()->Is<ast::Override>()) {
         constant.is_spec_op = true;
-        constant.constant_id = global->ConstantId();
+        constant.constant_id = global->OverrideId().value;
     }
 
     Switch(
@@ -4135,9 +4135,9 @@
     return SpvStorageClassMax;
 }
 
-SpvBuiltIn Builder::ConvertBuiltin(ast::Builtin builtin, ast::StorageClass storage) {
+SpvBuiltIn Builder::ConvertBuiltin(ast::BuiltinValue builtin, ast::StorageClass storage) {
     switch (builtin) {
-        case ast::Builtin::kPosition:
+        case ast::BuiltinValue::kPosition:
             if (storage == ast::StorageClass::kIn) {
                 return SpvBuiltInFragCoord;
             } else if (storage == ast::StorageClass::kOut) {
@@ -4146,32 +4146,32 @@
                 TINT_ICE(Writer, builder_.Diagnostics()) << "invalid storage class for builtin";
                 break;
             }
-        case ast::Builtin::kVertexIndex:
+        case ast::BuiltinValue::kVertexIndex:
             return SpvBuiltInVertexIndex;
-        case ast::Builtin::kInstanceIndex:
+        case ast::BuiltinValue::kInstanceIndex:
             return SpvBuiltInInstanceIndex;
-        case ast::Builtin::kFrontFacing:
+        case ast::BuiltinValue::kFrontFacing:
             return SpvBuiltInFrontFacing;
-        case ast::Builtin::kFragDepth:
+        case ast::BuiltinValue::kFragDepth:
             return SpvBuiltInFragDepth;
-        case ast::Builtin::kLocalInvocationId:
+        case ast::BuiltinValue::kLocalInvocationId:
             return SpvBuiltInLocalInvocationId;
-        case ast::Builtin::kLocalInvocationIndex:
+        case ast::BuiltinValue::kLocalInvocationIndex:
             return SpvBuiltInLocalInvocationIndex;
-        case ast::Builtin::kGlobalInvocationId:
+        case ast::BuiltinValue::kGlobalInvocationId:
             return SpvBuiltInGlobalInvocationId;
-        case ast::Builtin::kPointSize:
+        case ast::BuiltinValue::kPointSize:
             return SpvBuiltInPointSize;
-        case ast::Builtin::kWorkgroupId:
+        case ast::BuiltinValue::kWorkgroupId:
             return SpvBuiltInWorkgroupId;
-        case ast::Builtin::kNumWorkgroups:
+        case ast::BuiltinValue::kNumWorkgroups:
             return SpvBuiltInNumWorkgroups;
-        case ast::Builtin::kSampleIndex:
+        case ast::BuiltinValue::kSampleIndex:
             push_capability(SpvCapabilitySampleRateShading);
             return SpvBuiltInSampleId;
-        case ast::Builtin::kSampleMask:
+        case ast::BuiltinValue::kSampleMask:
             return SpvBuiltInSampleMask;
-        case ast::Builtin::kNone:
+        case ast::BuiltinValue::kInvalid:
             break;
     }
     return SpvBuiltInMax;
@@ -4241,7 +4241,7 @@
             return SpvImageFormatRgba32i;
         case ast::TexelFormat::kRgba32Float:
             return SpvImageFormatRgba32f;
-        case ast::TexelFormat::kNone:
+        case ast::TexelFormat::kInvalid:
             return SpvImageFormatUnknown;
     }
     return SpvImageFormatUnknown;
diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h
index f6bb93f..a0eff10 100644
--- a/src/tint/writer/spirv/builder.h
+++ b/src/tint/writer/spirv/builder.h
@@ -211,7 +211,7 @@
     /// @param builtin the builtin to convert
     /// @param storage the storage class that this builtin is being used with
     /// @returns the SPIR-V builtin or SpvBuiltInMax on error.
-    SpvBuiltIn ConvertBuiltin(ast::Builtin builtin, ast::StorageClass storage);
+    SpvBuiltIn ConvertBuiltin(ast::BuiltinValue builtin, ast::StorageClass storage);
 
     /// Converts an interpolate attribute to SPIR-V decorations and pushes a
     /// capability if needed.
diff --git a/src/tint/writer/spirv/builder_builtin_test.cc b/src/tint/writer/spirv/builder_builtin_test.cc
index c4bf27e..4ed4826 100644
--- a/src/tint/writer/spirv/builder_builtin_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_test.cc
@@ -918,9 +918,11 @@
 using Builtin_Builtin_ThreeParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_ThreeParam_Float_Test, Call_Scalar) {
     auto param = GetParam();
-    auto* expr = Call(param.name, 1_f, 1_f, 1_f);
+    auto* decl = Decl(Var("a", nullptr, Expr(1_f)));
+    auto* expr = Call(param.name, Expr("a"), 1_f, 1_f);
     auto* func = Func("a_func", {}, ty.void_(),
                       {
+                          decl,
                           Assign(Phony(), expr),
                       });
 
@@ -929,17 +931,23 @@
     ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
     auto got = DumpBuilder(b);
-    auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+    auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
+OpName %7 "a"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%6 = OpTypeFloat 32
-%8 = OpConstant %6 1
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
                   param.op +
-                  R"( %8 %8 %8
+                  R"( %12 %6 %6
 OpReturn
 OpFunctionEnd
 )";
@@ -948,9 +956,11 @@
 
 TEST_P(Builtin_Builtin_ThreeParam_Float_Test, Call_Vector) {
     auto param = GetParam();
-    auto* expr = Call(param.name, vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f));
+    auto* decl = Decl(Var("a", nullptr, vec2<f32>(1_f, 1_f)));
+    auto* expr = Call(param.name, Expr("a"), vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f));
     auto* func = Func("a_func", {}, ty.void_(),
                       {
+                          decl,
                           Assign(Phony(), expr),
                       });
 
@@ -959,19 +969,25 @@
     ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
     auto got = DumpBuilder(b);
-    auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+    auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
+OpName %9 "a"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
                   param.op +
-                  R"( %10 %10 %10
+                  R"( %14 %8 %8
 OpReturn
 OpFunctionEnd
 )";
@@ -1305,9 +1321,11 @@
 using Builtin_Builtin_ThreeParam_Sint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_ThreeParam_Sint_Test, Call_Scalar) {
     auto param = GetParam();
-    auto* expr = Call(param.name, 1_i, 1_i, 1_i);
+    auto* decl = Decl(Var("a", nullptr, Expr(1_i)));
+    auto* expr = Call(param.name, Expr("a"), 1_i, 1_i);
     auto* func = Func("a_func", {}, ty.void_(),
                       {
+                          decl,
                           Assign(Phony(), expr),
                       });
 
@@ -1316,17 +1334,23 @@
     ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
     auto got = DumpBuilder(b);
-    auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+    auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
+OpName %7 "a"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%6 = OpTypeInt 32 1
-%8 = OpConstant %6 1
+%5 = OpTypeInt 32 1
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
                   param.op +
-                  R"( %8 %8 %8
+                  R"( %12 %6 %6
 OpReturn
 OpFunctionEnd
 )";
@@ -1335,9 +1359,11 @@
 
 TEST_P(Builtin_Builtin_ThreeParam_Sint_Test, Call_Vector) {
     auto param = GetParam();
-    auto* expr = Call(param.name, vec2<i32>(1_i, 1_i), vec2<i32>(1_i, 1_i), vec2<i32>(1_i, 1_i));
+    auto* decl = Decl(Var("a", nullptr, vec2<i32>(1_i, 1_i)));
+    auto* expr = Call(param.name, Expr("a"), vec2<i32>(1_i, 1_i), vec2<i32>(1_i, 1_i));
     auto* func = Func("a_func", {}, ty.void_(),
                       {
+                          decl,
                           Assign(Phony(), expr),
                       });
 
@@ -1346,19 +1372,25 @@
     ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
     auto got = DumpBuilder(b);
-    auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+    auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
+OpName %9 "a"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%7 = OpTypeInt 32 1
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeInt 32 1
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
                   param.op +
-                  R"( %10 %10 %10
+                  R"( %14 %8 %8
 OpReturn
 OpFunctionEnd
 )";
@@ -1371,9 +1403,11 @@
 using Builtin_Builtin_ThreeParam_Uint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_ThreeParam_Uint_Test, Call_Scalar) {
     auto param = GetParam();
-    auto* expr = Call(param.name, 1_u, 1_u, 1_u);
+    auto* decl = Decl(Var("a", nullptr, Expr(1_u)));
+    auto* expr = Call(param.name, Expr("a"), 1_u, 1_u);
     auto* func = Func("a_func", {}, ty.void_(),
                       {
+                          decl,
                           Assign(Phony(), expr),
                       });
 
@@ -1382,17 +1416,23 @@
     ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
     auto got = DumpBuilder(b);
-    auto expect = R"(%7 = OpExtInstImport "GLSL.std.450"
+    auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
+OpName %7 "a"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%6 = OpTypeInt 32 0
-%8 = OpConstant %6 1
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %7 )" +
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+%12 = OpLoad %5 %7
+%10 = OpExtInst %5 %11 )" +
                   param.op +
-                  R"( %8 %8 %8
+                  R"( %12 %6 %6
 OpReturn
 OpFunctionEnd
 )";
@@ -1401,9 +1441,11 @@
 
 TEST_P(Builtin_Builtin_ThreeParam_Uint_Test, Call_Vector) {
     auto param = GetParam();
-    auto* expr = Call(param.name, vec2<u32>(1_u, 1_u), vec2<u32>(1_u, 1_u), vec2<u32>(1_u, 1_u));
+    auto* decl = Decl(Var("a", nullptr, vec2<u32>(1_u, 1_u)));
+    auto* expr = Call(param.name, Expr("a"), vec2<u32>(1_u, 1_u), vec2<u32>(1_u, 1_u));
     auto* func = Func("a_func", {}, ty.void_(),
                       {
+                          decl,
                           Assign(Phony(), expr),
                       });
 
@@ -1412,19 +1454,25 @@
     ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
     auto got = DumpBuilder(b);
-    auto expect = R"(%8 = OpExtInstImport "GLSL.std.450"
+    auto expect = R"(%13 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
+OpName %9 "a"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%7 = OpTypeInt 32 0
-%6 = OpTypeVector %7 2
-%9 = OpConstant %7 1
-%10 = OpConstantComposite %6 %9 %9
+%6 = OpTypeInt 32 0
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
 %3 = OpFunction %2 None %1
 %4 = OpLabel
-%5 = OpExtInst %6 %8 )" +
+%9 = OpVariable %10 Function %11
+OpStore %9 %8
+%14 = OpLoad %5 %9
+%12 = OpExtInst %5 %13 )" +
                   param.op +
-                  R"( %10 %10 %10
+                  R"( %14 %8 %8
 OpReturn
 OpFunctionEnd
 )";
@@ -2757,7 +2805,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);
+                            ast::Extension::kChromiumExperimentalDp4A);
     AST().AddEnable(ext);
 
     auto* val1 = Var("val1", ty.u32());
@@ -2797,7 +2845,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);
+                            ast::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 8e9d857..2c10ab3 100644
--- a/src/tint/writer/spirv/builder_entry_point_test.cc
+++ b/src/tint/writer/spirv/builder_entry_point_test.cc
@@ -15,8 +15,8 @@
 #include <memory>
 
 #include "gtest/gtest.h"
-#include "src/tint/ast/builtin.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"
@@ -42,7 +42,7 @@
     //              @location(1) loc1 : f32) {
     //   var col : f32 = (coord.x * loc1);
     // }
-    auto* coord = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
+    auto* coord = Param("coord", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)});
     auto* loc1 = Param("loc1", ty.f32(), {Location(1u)});
     auto* mul = Mul(Expr(MemberAccessor("coord", "x")), Expr("loc1"));
     auto* col = Var("col", ty.f32(), ast::StorageClass::kNone, mul);
@@ -199,7 +199,7 @@
     auto* interface = Structure(
         "Interface", {
                          Member("value", ty.f32(), {Location(1u)}),
-                         Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                         Member("pos", ty.vec4<f32>(), {Builtin(ast::BuiltinValue::kPosition)}),
                      });
 
     auto* vert_retval = Construct(ty.Of(interface), 42_f, Construct(ty.vec4<f32>()));
@@ -211,7 +211,7 @@
          {
              Return(MemberAccessor(Expr("inputs"), "value")),
          },
-         {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
+         {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::BuiltinValue::kFragDepth)});
 
     spirv::Builder& b = SanitizeAndBuild();
 
@@ -302,7 +302,7 @@
 }
 
 TEST_F(BuilderTest, SampleIndex_SampleRateShadingCapability) {
-    Func("main", {Param("sample_index", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})},
+    Func("main", {Param("sample_index", ty.u32(), {Builtin(ast::BuiltinValue::kSampleIndex)})},
          ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
     spirv::Builder& b = SanitizeAndBuild();
diff --git a/src/tint/writer/spirv/builder_function_attribute_test.cc b/src/tint/writer/spirv/builder_function_attribute_test.cc
index c309813..ab1fa0b 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 @@
     ast::StatementList body;
     if (params.stage == ast::PipelineStage::kVertex) {
         ret_type = ty.vec4<f32>();
-        ret_type_attrs.push_back(Builtin(ast::Builtin::kPosition));
+        ret_type_attrs.push_back(Builtin(ast::BuiltinValue::kPosition));
         body.push_back(Return(Construct(ty.vec4<f32>())));
     } else {
         ret_type = ty.void_();
@@ -250,7 +250,7 @@
              Stage(ast::PipelineStage::kFragment),
          },
          {
-             Builtin(ast::Builtin::kFragDepth),
+             Builtin(ast::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 f29b78e..5d1a5b0 100644
--- a/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -422,7 +422,7 @@
 }
 
 struct BuiltinData {
-    ast::Builtin builtin;
+    ast::BuiltinValue builtin;
     ast::StorageClass storage;
     SpvBuiltIn result;
 };
@@ -442,28 +442,31 @@
     BuilderTest_Type,
     BuiltinDataTest,
     testing::Values(
-        BuiltinData{ast::Builtin::kNone, ast::StorageClass::kNone, SpvBuiltInMax},
-        BuiltinData{ast::Builtin::kPosition, ast::StorageClass::kIn, SpvBuiltInFragCoord},
-        BuiltinData{ast::Builtin::kPosition, ast::StorageClass::kOut, SpvBuiltInPosition},
+        BuiltinData{ast::BuiltinValue::kInvalid, ast::StorageClass::kNone, SpvBuiltInMax},
+        BuiltinData{ast::BuiltinValue::kPosition, ast::StorageClass::kIn, SpvBuiltInFragCoord},
+        BuiltinData{ast::BuiltinValue::kPosition, ast::StorageClass::kOut, SpvBuiltInPosition},
         BuiltinData{
-            ast::Builtin::kVertexIndex,
+            ast::BuiltinValue::kVertexIndex,
             ast::StorageClass::kIn,
             SpvBuiltInVertexIndex,
         },
-        BuiltinData{ast::Builtin::kInstanceIndex, ast::StorageClass::kIn, SpvBuiltInInstanceIndex},
-        BuiltinData{ast::Builtin::kFrontFacing, ast::StorageClass::kIn, SpvBuiltInFrontFacing},
-        BuiltinData{ast::Builtin::kFragDepth, ast::StorageClass::kOut, SpvBuiltInFragDepth},
-        BuiltinData{ast::Builtin::kLocalInvocationId, ast::StorageClass::kIn,
+        BuiltinData{ast::BuiltinValue::kInstanceIndex, ast::StorageClass::kIn,
+                    SpvBuiltInInstanceIndex},
+        BuiltinData{ast::BuiltinValue::kFrontFacing, ast::StorageClass::kIn, SpvBuiltInFrontFacing},
+        BuiltinData{ast::BuiltinValue::kFragDepth, ast::StorageClass::kOut, SpvBuiltInFragDepth},
+        BuiltinData{ast::BuiltinValue::kLocalInvocationId, ast::StorageClass::kIn,
                     SpvBuiltInLocalInvocationId},
-        BuiltinData{ast::Builtin::kLocalInvocationIndex, ast::StorageClass::kIn,
+        BuiltinData{ast::BuiltinValue::kLocalInvocationIndex, ast::StorageClass::kIn,
                     SpvBuiltInLocalInvocationIndex},
-        BuiltinData{ast::Builtin::kGlobalInvocationId, ast::StorageClass::kIn,
+        BuiltinData{ast::BuiltinValue::kGlobalInvocationId, ast::StorageClass::kIn,
                     SpvBuiltInGlobalInvocationId},
-        BuiltinData{ast::Builtin::kWorkgroupId, ast::StorageClass::kIn, SpvBuiltInWorkgroupId},
-        BuiltinData{ast::Builtin::kNumWorkgroups, ast::StorageClass::kIn, SpvBuiltInNumWorkgroups},
-        BuiltinData{ast::Builtin::kSampleIndex, ast::StorageClass::kIn, SpvBuiltInSampleId},
-        BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kIn, SpvBuiltInSampleMask},
-        BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kOut, SpvBuiltInSampleMask}));
+        BuiltinData{ast::BuiltinValue::kWorkgroupId, ast::StorageClass::kIn, SpvBuiltInWorkgroupId},
+        BuiltinData{ast::BuiltinValue::kNumWorkgroups, ast::StorageClass::kIn,
+                    SpvBuiltInNumWorkgroups},
+        BuiltinData{ast::BuiltinValue::kSampleIndex, ast::StorageClass::kIn, SpvBuiltInSampleId},
+        BuiltinData{ast::BuiltinValue::kSampleMask, ast::StorageClass::kIn, SpvBuiltInSampleMask},
+        BuiltinData{ast::BuiltinValue::kSampleMask, ast::StorageClass::kOut,
+                    SpvBuiltInSampleMask}));
 
 TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
     // struct A {
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index 50f23fc..6ca7083 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -345,7 +345,7 @@
 
 bool GeneratorImpl::EmitImageFormat(std::ostream& out, const ast::TexelFormat fmt) {
     switch (fmt) {
-        case ast::TexelFormat::kNone:
+        case ast::TexelFormat::kInvalid:
             diagnostics_.add_error(diag::System::Writer, "unknown image format");
             return false;
         default:
diff --git a/src/tint/writer/wgsl/generator_impl_function_test.cc b/src/tint/writer/wgsl/generator_impl_function_test.cc
index 0673858..a7dab7a 100644
--- a/src/tint/writer/wgsl/generator_impl_function_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_function_test.cc
@@ -99,7 +99,7 @@
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_EntryPoint_Parameters) {
     auto* vec4 = ty.vec4<f32>();
-    auto* coord = Param("coord", vec4, {Builtin(ast::Builtin::kPosition)});
+    auto* coord = Param("coord", vec4, {Builtin(ast::BuiltinValue::kPosition)});
     auto* loc1 = Param("loc1", ty.f32(), {Location(1u)});
     auto* func = Func("frag_main", {coord, loc1}, ty.void_(), {},
                       {
diff --git a/src/tint/writer/wgsl/generator_impl_type_test.cc b/src/tint/writer/wgsl/generator_impl_type_test.cc
index 2e54620..9536b5b 100644
--- a/src/tint/writer/wgsl/generator_impl_type_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_type_test.cc
@@ -270,9 +270,9 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithEntryPointAttributes) {
-    auto* s = Structure(
-        "S", ast::StructMemberList{Member("a", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)}),
-                                   Member("b", ty.f32(), {Location(2u)})});
+    auto* s = Structure("S", ast::StructMemberList{
+                                 Member("a", ty.u32(), {Builtin(ast::BuiltinValue::kVertexIndex)}),
+                                 Member("b", ty.f32(), {Location(2u)})});
 
     GeneratorImpl& gen = Build();